Qt 4.8
qfsfileengine_unix.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qplatformdefs.h"
43 #include "qabstractfileengine.h"
44 #include "private/qfsfileengine_p.h"
45 #include "private/qcore_unix_p.h"
46 #include "qfilesystementry_p.h"
47 #include "qfilesystemengine_p.h"
48 
49 #ifndef QT_NO_FSFILEENGINE
50 
51 #include "qfile.h"
52 #include "qdir.h"
53 #include "qdatetime.h"
54 #include "qvarlengtharray.h"
55 
56 #include <sys/mman.h>
57 #include <stdlib.h>
58 #include <limits.h>
59 #if defined(Q_OS_SYMBIAN)
60 # include <sys/syslimits.h>
61 # include <f32file.h>
62 # include <pathinfo.h>
63 # include "private/qcore_symbian_p.h"
64 #endif
65 #include <errno.h>
66 #if !defined(QWS) && defined(Q_OS_MAC)
67 # include <private/qcore_mac_p.h>
68 #endif
69 
71 
72 #if defined(Q_OS_SYMBIAN)
73 
78 static bool isRelativePathSymbian(const QString& fileName)
79 {
80  return !(fileName.startsWith(QLatin1Char('/'))
81  || (fileName.length() >= 2
82  && ((fileName.at(0).isLetter() && fileName.at(1) == QLatin1Char(':'))
83  || (fileName.at(0) == QLatin1Char('/') && fileName.at(1) == QLatin1Char('/')))));
84 }
85 
86 #endif
87 
88 #ifndef Q_OS_SYMBIAN
89 
97 static inline QByteArray openModeToFopenMode(QIODevice::OpenMode flags, const QFileSystemEntry &fileEntry,
98  QFileSystemMetaData &metaData)
99 {
100  QByteArray mode;
101  if ((flags & QIODevice::ReadOnly) && !(flags & QIODevice::Truncate)) {
102  mode = "rb";
103  if (flags & QIODevice::WriteOnly) {
105  if (!fileEntry.isEmpty()
107  && metaData.isFile()) {
108  mode += '+';
109  } else {
110  mode = "wb+";
111  }
112  }
113  } else if (flags & QIODevice::WriteOnly) {
114  mode = "wb";
115  if (flags & QIODevice::ReadOnly)
116  mode += '+';
117  }
118  if (flags & QIODevice::Append) {
119  mode = "ab";
120  if (flags & QIODevice::ReadOnly)
121  mode += '+';
122  }
123 
124 #if defined(__GLIBC__) && (__GLIBC__ * 0x100 + __GLIBC_MINOR__) >= 0x0207
125  // must be glibc >= 2.7
126  mode += 'e';
127 #endif
128 
129  return mode;
130 }
131 #endif
132 
141 static inline int openModeToOpenFlags(QIODevice::OpenMode mode)
142 {
143  int oflags = QT_OPEN_RDONLY;
144 #ifdef QT_LARGEFILE_SUPPORT
145  oflags |= QT_OPEN_LARGEFILE;
146 #endif
147 
148  if ((mode & QFile::ReadWrite) == QFile::ReadWrite) {
149  oflags = QT_OPEN_RDWR | QT_OPEN_CREAT;
150  } else if (mode & QFile::WriteOnly) {
151  oflags = QT_OPEN_WRONLY | QT_OPEN_CREAT;
152  }
153 
154  if (mode & QFile::Append) {
155  oflags |= QT_OPEN_APPEND;
156  } else if (mode & QFile::WriteOnly) {
157  if ((mode & QFile::Truncate) || !(mode & QFile::ReadOnly))
158  oflags |= QT_OPEN_TRUNC;
159  }
160 
161  return oflags;
162 }
163 
164 #ifndef Q_OS_SYMBIAN
165 
174 static inline bool setCloseOnExec(int fd)
175 {
176  return fd != -1 && fcntl(fd, F_SETFD, FD_CLOEXEC) != -1;
177 }
178 #endif
179 
180 #ifdef Q_OS_SYMBIAN
181 
184 bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
185 {
187 
188  fh = 0;
189  fd = -1;
190 
191  QString fn(QFileSystemEngine::absoluteName(fileEntry).nativeFilePath());
192  RFs& fs = qt_s60GetRFs();
193 
194  TUint symbianMode = 0;
195 
196  if(openMode & QIODevice::ReadOnly)
197  symbianMode |= EFileRead;
198  if(openMode & QIODevice::WriteOnly)
199  symbianMode |= EFileWrite;
200  if(openMode & QIODevice::Text)
201  symbianMode |= EFileStreamText;
202 
203  if (openMode & QFile::Unbuffered) {
204  if (openMode & QIODevice::WriteOnly)
205  symbianMode |= 0x00001000; //EFileWriteDirectIO;
206  // ### Unbuffered read is not used, because it prevents file open in /resource
207  // ### and has no obvious benefits
208  } else {
209  if (openMode & QIODevice::WriteOnly)
210  symbianMode |= 0x00000800; //EFileWriteBuffered;
211  // use implementation defaults for read buffering
212  }
213 
214  // Until Qt supports file sharing, we can't support EFileShareReadersOrWriters safely,
215  // but Qt does this on other platforms and autotests rely on it.
216  // The reason is that Unix locks are only advisory - the application needs to test the
217  // lock after opening the file. Symbian and Windows locks are mandatory - opening a
218  // locked file will fail.
219  symbianMode |= EFileShareReadersOrWriters;
220 
221  TInt r;
222  //note QIODevice::Truncate only has meaning for read/write access
223  //write-only files are always truncated unless append is specified
224  //reference openModeToOpenFlags in qfsfileengine_unix.cpp
225  if ((openMode & QIODevice::Truncate) || (!(openMode & QIODevice::ReadOnly) && !(openMode & QIODevice::Append))) {
226  r = symbianFile.Replace(fs, qt_QString2TPtrC(fn), symbianMode);
227  } else {
228  r = symbianFile.Open(fs, qt_QString2TPtrC(fn), symbianMode);
229  if (r == KErrNotFound && (openMode & QIODevice::WriteOnly)) {
230  r = symbianFile.Create(fs, qt_QString2TPtrC(fn), symbianMode);
231  }
232  }
233 
234  if (r == KErrNone) {
235 #ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
236  TInt64 size;
237 #else
238  TInt size;
239 #endif
240  r = symbianFile.Size(size);
241  if (r==KErrNone) {
242  if (openMode & QIODevice::Append)
243  symbianFilePos = size;
244  else
245  symbianFilePos = 0;
246  //TODO: port this (QFileSystemMetaData in open?)
247  //cachedSize = size;
248  }
249  }
250 
251  if (r != KErrNone) {
253  symbianFile.Close();
254  return false;
255  }
256 
257  closeFileHandle = true;
258  return true;
259 }
260 
269 bool QFSFileEngine::open(QIODevice::OpenMode openMode, const RFile &file, QFile::FileHandleFlags handleFlags)
270 {
272 
273  // Append implies WriteOnly.
274  if (openMode & QFile::Append)
275  openMode |= QFile::WriteOnly;
276 
277  // WriteOnly implies Truncate if neither ReadOnly nor Append are sent.
278  if ((openMode & QFile::WriteOnly) && !(openMode & (QFile::ReadOnly | QFile::Append)))
279  openMode |= QFile::Truncate;
280 
281  d->openMode = openMode;
282  d->lastFlushFailed = false;
283  d->closeFileHandle = (handleFlags & QFile::AutoCloseHandle);
284  d->fileEntry.clear();
285  d->fh = 0;
286  d->fd = -1;
287  d->tried_stat = 0;
288 
289 #ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
290  //RFile64 adds only functions to RFile, no data members
291  d->symbianFile = static_cast<const RFile64&>(file);
292 #else
293  d->symbianFile = file;
294 #endif
295  TInt ret;
296  d->symbianFilePos = 0;
297  if (openMode & QFile::Append) {
298  // Seek to the end when in Append mode.
299  ret = d->symbianFile.Size(d->symbianFilePos);
300  } else {
301  // Seek to current otherwise
302  ret = d->symbianFile.Seek(ESeekCurrent, d->symbianFilePos);
303  }
304 
305  if (ret != KErrNone) {
307 
308  d->openMode = QIODevice::NotOpen;
309 #ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
310  d->symbianFile = RFile64();
311 #else
312  d->symbianFile = RFile();
313 #endif
314  return false;
315  }
316 
317  // Extract filename (best effort)
318  TFileName fn;
319  TInt err = d->symbianFile.FullName(fn);
320  if (err == KErrNone)
321  d->fileEntry = QFileSystemEntry(qt_TDesC2QString(fn), QFileSystemEntry::FromNativePath());
322  else
323  d->fileEntry.clear();
324 
325  return true;
326 }
327 #else
328 
331 bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
332 {
334 
335  if (openMode & QIODevice::Unbuffered) {
336  int flags = openModeToOpenFlags(openMode);
337 
338  // Try to open the file in unbuffered mode.
339  do {
340  fd = QT_OPEN(fileEntry.nativeFilePath().constData(), flags, 0666);
341  } while (fd == -1 && errno == EINTR);
342 
343  // On failure, return and report the error.
344  if (fd == -1) {
345  q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
347  return false;
348  }
349 
350  if (!(openMode & QIODevice::WriteOnly)) {
351  // we don't need this check if we tried to open for writing because then
352  // we had received EISDIR anyway.
354  && metaData.isDirectory()) {
355  q->setError(QFile::OpenError, QLatin1String("file to open is a directory"));
356  QT_CLOSE(fd);
357  return false;
358  }
359  }
360 
361  // Seek to the end when in Append mode.
362  if (flags & QFile::Append) {
363  int ret;
364  do {
365  ret = QT_LSEEK(fd, 0, SEEK_END);
366  } while (ret == -1 && errno == EINTR);
367 
368  if (ret == -1) {
369  q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
370  qt_error_string(int(errno)));
371  return false;
372  }
373  }
374 
375  fh = 0;
376  } else {
377  QByteArray fopenMode = openModeToFopenMode(openMode, fileEntry, metaData);
378 
379  // Try to open the file in buffered mode.
380  do {
381  fh = QT_FOPEN(fileEntry.nativeFilePath().constData(), fopenMode.constData());
382  } while (!fh && errno == EINTR);
383 
384  // On failure, return and report the error.
385  if (!fh) {
386  q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
387  qt_error_string(int(errno)));
388  return false;
389  }
390 
391  if (!(openMode & QIODevice::WriteOnly)) {
392  // we don't need this check if we tried to open for writing because then
393  // we had received EISDIR anyway.
395  && metaData.isDirectory()) {
396  q->setError(QFile::OpenError, QLatin1String("file to open is a directory"));
397  fclose(fh);
398  return false;
399  }
400  }
401 
402  setCloseOnExec(fileno(fh)); // ignore failure
403 
404  // Seek to the end when in Append mode.
405  if (openMode & QIODevice::Append) {
406  int ret;
407  do {
408  ret = QT_FSEEK(fh, 0, SEEK_END);
409  } while (ret == -1 && errno == EINTR);
410 
411  if (ret == -1) {
412  q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
413  qt_error_string(int(errno)));
414  return false;
415  }
416  }
417 
418  fd = -1;
419  }
420 
421  closeFileHandle = true;
422  return true;
423 }
424 #endif
425 
430 {
431  return closeFdFh();
432 }
433 
439 {
440 #ifdef Q_OS_SYMBIAN
441  if (symbianFile.SubSessionHandle())
442  return (KErrNone == symbianFile.Flush());
443 #endif
444  return fh ? flushFh() : fd != -1;
445 }
446 
451 {
453 
454 #ifdef Q_OS_SYMBIAN
455  if (symbianFile.SubSessionHandle()) {
456  if(len > KMaxTInt) {
457  //this check is more likely to catch a corrupt length, since it isn't possible to allocate 2GB buffers (yet..)
458  q->setError(QFile::ReadError, QLatin1String("Maximum 2GB in single read on this platform"));
459  return -1;
460  }
461  TPtr8 ptr(reinterpret_cast<TUint8*>(data), static_cast<TInt>(len));
462  TInt r = symbianFile.Read(symbianFilePos, ptr);
463  if (r != KErrNone)
464  {
466  return -1;
467  }
468  symbianFilePos += ptr.Length();
469  return qint64(ptr.Length());
470  }
471 #endif
472  if (fh && nativeIsSequential()) {
473  size_t readBytes = 0;
474  int oldFlags = fcntl(QT_FILENO(fh), F_GETFL);
475  for (int i = 0; i < 2; ++i) {
476  // Unix: Make the underlying file descriptor non-blocking
477  if ((oldFlags & O_NONBLOCK) == 0)
478  fcntl(QT_FILENO(fh), F_SETFL, oldFlags | O_NONBLOCK);
479 
480  // Cross platform stdlib read
481  size_t read = 0;
482  do {
483  read = fread(data + readBytes, 1, size_t(len - readBytes), fh);
484  } while (read == 0 && !feof(fh) && errno == EINTR);
485  if (read > 0) {
486  readBytes += read;
487  break;
488  } else {
489  if (readBytes)
490  break;
491  readBytes = read;
492  }
493 
494  // Unix: Restore the blocking state of the underlying socket
495  if ((oldFlags & O_NONBLOCK) == 0) {
496  fcntl(QT_FILENO(fh), F_SETFL, oldFlags);
497  if (readBytes == 0) {
498  int readByte = 0;
499  do {
500  readByte = fgetc(fh);
501  } while (readByte == -1 && errno == EINTR);
502  if (readByte != -1) {
503  *data = uchar(readByte);
504  readBytes += 1;
505  } else {
506  break;
507  }
508  }
509  }
510  }
511  // Unix: Restore the blocking state of the underlying socket
512  if ((oldFlags & O_NONBLOCK) == 0) {
513  fcntl(QT_FILENO(fh), F_SETFL, oldFlags);
514  }
515  if (readBytes == 0 && !feof(fh)) {
516  // if we didn't read anything and we're not at EOF, it must be an error
517  q->setError(QFile::ReadError, qt_error_string(int(errno)));
518  return -1;
519  }
520  return readBytes;
521  }
522 
523  return readFdFh(data, len);
524 }
525 
530 {
531  return readLineFdFh(data, maxlen);
532 }
533 
538 {
539 #ifdef Q_OS_SYMBIAN
541  if (symbianFile.SubSessionHandle()) {
542  if(len > KMaxTInt) {
543  //this check is more likely to catch a corrupt length, since it isn't possible to allocate 2GB buffers (yet..)
544  q->setError(QFile::WriteError, QLatin1String("Maximum 2GB in single write on this platform"));
545  return -1;
546  }
547  const TPtrC8 ptr(reinterpret_cast<const TUint8*>(data), static_cast<TInt>(len));
548 #ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
549  TInt64 eofpos = 0;
550 #else
551  TInt eofpos = 0;
552 #endif
553  //The end of file position is not cached because QFile is read/write sharable, therefore another
554  //process may have altered the file size.
555  TInt r = symbianFile.Seek(ESeekEnd, eofpos);
556  if (r == KErrNone && symbianFilePos > eofpos) {
557  //seek position is beyond end of file so file needs to be extended before write.
558  //note that SetSize does not zero-initialise (c.f. posix lseek)
559  r = symbianFile.SetSize(symbianFilePos);
560  }
561  if (r == KErrNone) {
562  //write to specific position in the file (i.e. use our own cursor rather than calling seek)
563  r = symbianFile.Write(symbianFilePos, ptr);
564  }
565  if (r != KErrNone) {
567  return -1;
568  }
569  symbianFilePos += len;
570  return len;
571  }
572 #endif
573  return writeFdFh(data, len);
574 }
575 
580 {
581 #ifdef Q_OS_SYMBIAN
582  const Q_Q(QFSFileEngine);
583  if (symbianFile.SubSessionHandle()) {
584  return symbianFilePos;
585  }
586 #endif
587  return posFdFh();
588 }
589 
594 {
595 #ifdef Q_OS_SYMBIAN
597  if (symbianFile.SubSessionHandle()) {
598 #ifndef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
599  if(pos > KMaxTInt) {
600  q->setError(QFile::PositionError, QLatin1String("Maximum 2GB file position on this platform"));
601  return false;
602  }
603 #endif
604  symbianFilePos = pos;
605  return true;
606  }
607 #endif
608  return seekFdFh(pos);
609 }
610 
615 {
616  return fh ? fileno(fh) : fd;
617 }
618 
619 #if defined(Q_OS_SYMBIAN) && !defined(QT_SYMBIAN_USE_NATIVE_FILEMAP)
620 int QFSFileEnginePrivate::getMapHandle()
621 {
622  if (symbianFile.SubSessionHandle()) {
623  // Symbian file handle can't be used for open C mmap() so open the file with open C as well.
624  if (fileHandleForMaps < 0) {
625  int flags = openModeToOpenFlags(openMode);
626  flags &= ~(O_CREAT | O_TRUNC);
627  fileHandleForMaps = ::wopen((wchar_t*)(fileEntry.nativeFilePath().utf16()), flags, 0666);
628  }
629  return fileHandleForMaps;
630  }
631  return nativeHandle();
632 }
633 #endif
634 
639 {
640 #ifdef Q_OS_SYMBIAN
641  if (symbianFile.SubSessionHandle())
642  return false;
643 #endif
644  return isSequentialFdFh();
645 }
646 
648 {
651  bool ret = QFileSystemEngine::removeFile(d->fileEntry, error);
652  d->metaData.clear();
653  if (!ret) {
654  setError(QFile::RemoveError, error.toString());
655  }
656  return ret;
657 }
658 
659 bool QFSFileEngine::copy(const QString &newName)
660 {
663  bool ret = QFileSystemEngine::copyFile(d->fileEntry, QFileSystemEntry(newName), error);
664  if (!ret) {
665  setError(QFile::CopyError, error.toString());
666  }
667  return ret;
668 }
669 
670 bool QFSFileEngine::rename(const QString &newName)
671 {
674  bool ret = QFileSystemEngine::renameFile(d->fileEntry, QFileSystemEntry(newName), error);
675 
676  if (!ret) {
677  setError(QFile::RenameError, error.toString());
678  }
679 
680  return ret;
681 }
682 
683 bool QFSFileEngine::link(const QString &newName)
684 {
687  bool ret = QFileSystemEngine::createLink(d->fileEntry, QFileSystemEntry(newName), error);
688  if (!ret) {
689  setError(QFile::RenameError, error.toString());
690  }
691  return ret;
692 }
693 
695 {
696 #ifdef Q_OS_SYMBIAN
697  const Q_Q(QFSFileEngine);
698  if (symbianFile.SubSessionHandle()) {
699 #ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
700  qint64 size;
701 #else
702  TInt size;
703 #endif
704  TInt err = symbianFile.Size(size);
705  if(err != KErrNone) {
707  return 0;
708  }
709  return size;
710  }
711 #endif
712  return sizeFdFh();
713 }
714 
715 bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const
716 {
717  return QFileSystemEngine::createDirectory(QFileSystemEntry(name), createParentDirectories);
718 }
719 
720 bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const
721 {
722  return QFileSystemEngine::removeDirectory(QFileSystemEntry(name), recurseParentDirectories);
723 }
724 
726 {
727 #if defined(Q_OS_SYMBIAN)
728  return false;
729 #else
730  return true;
731 #endif
732 }
733 
735 {
737 }
738 
740 {
742 }
743 
745 {
747 }
748 
750 {
752 }
753 
755 {
757 }
758 
760 {
761  QFileInfoList ret;
762 #if defined(Q_OS_SYMBIAN)
763  TDriveList driveList;
764  RFs rfs = qt_s60GetRFs();
765  TInt err = rfs.DriveList(driveList);
766  if (err == KErrNone) {
767  char driveName[] = "A:/";
768 
769  for (char i = 0; i < KMaxDrives; i++) {
770  if (driveList[i]) {
771  driveName[0] = 'A' + i;
772  ret.append(QFileInfo(QLatin1String(driveName)));
773  }
774  }
775  } else {
776  qWarning("QFSFileEngine::drives: Getting drives failed");
777  }
778 #else
779  ret.append(QFileInfo(rootPath()));
780 #endif
781  return ret;
782 }
783 
784 bool QFSFileEnginePrivate::doStat(QFileSystemMetaData::MetaDataFlags flags) const
785 {
786  if (!tried_stat || !metaData.hasFlags(flags)) {
787  tried_stat = 1;
788 
789  int localFd = fd;
790  if (fh && fileEntry.isEmpty())
791  localFd = QT_FILENO(fh);
792  if (localFd != -1)
794 
795  if (metaData.missingFlags(flags) && !fileEntry.isEmpty())
797  }
798 
799  return metaData.exists();
800 }
801 
803 {
806 
807  return metaData.isLink();
808 }
809 
813 QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(FileFlags type) const
814 {
815  Q_D(const QFSFileEngine);
816 
817  if (type & Refresh)
818  d->metaData.clear();
819 
820  QAbstractFileEngine::FileFlags ret = 0;
821 
822  if (type & FlagsMask)
823  ret |= LocalDiskFlag;
824 
825  bool exists;
826  {
827  QFileSystemMetaData::MetaDataFlags queryFlags = 0;
828 
829  queryFlags |= QFileSystemMetaData::MetaDataFlags(uint(type))
831 
832  if (type & TypesMask)
833  queryFlags |= QFileSystemMetaData::AliasType
838 
839  if (type & FlagsMask)
842 
843  queryFlags |= QFileSystemMetaData::LinkType;
844 
845  exists = d->doStat(queryFlags);
846  }
847 
848  if (!exists && !d->metaData.isLink())
849  return ret;
850 
851  if (exists && (type & PermsMask))
852  ret |= FileFlags(uint(d->metaData.permissions()));
853 
854  if (type & TypesMask) {
855  if (d->metaData.isAlias()) {
856  ret |= LinkType;
857  } else {
858  if ((type & LinkType) && d->metaData.isLink())
859  ret |= LinkType;
860  if (exists) {
861  if (d->metaData.isFile()) {
862  ret |= FileType;
863  } else if (d->metaData.isDirectory()) {
864  ret |= DirectoryType;
865  if ((type & BundleType) && d->metaData.isBundle())
866  ret |= BundleType;
867  }
868  }
869  }
870  }
871 
872  if (type & FlagsMask) {
873  if (exists)
874  ret |= ExistsFlag;
875  if (d->fileEntry.isRoot())
876  ret |= RootFlag;
877  else if (d->metaData.isHidden())
878  ret |= HiddenFlag;
879  }
880 
881  return ret;
882 }
883 
885 {
886  Q_D(const QFSFileEngine);
887  if (file == BundleName) {
888  return QFileSystemEngine::bundleName(d->fileEntry);
889  } else if (file == BaseName) {
890  return d->fileEntry.fileName();
891  } else if (file == PathName) {
892  return d->fileEntry.path();
893  } else if (file == AbsoluteName || file == AbsolutePathName) {
895  if (file == AbsolutePathName) {
896  return entry.path();
897  }
898  return entry.filePath();
899  } else if (file == CanonicalName || file == CanonicalPathName) {
900  QFileSystemEntry entry(QFileSystemEngine::canonicalName(d->fileEntry, d->metaData));
901  if (file == CanonicalPathName)
902  return entry.path();
903  return entry.filePath();
904  } else if (file == LinkName) {
905  if (d->isSymlink()) {
906  QFileSystemEntry entry = QFileSystemEngine::getLinkTarget(d->fileEntry, d->metaData);
907  return entry.filePath();
908  }
909  return QString();
910  }
911  return d->fileEntry.filePath();
912 }
913 
915 {
916  Q_D(const QFSFileEngine);
917 #if defined(Q_OS_SYMBIAN)
918  return isRelativePathSymbian(d->fileEntry.filePath());
919 #else
920  return d->fileEntry.filePath().length() ? d->fileEntry.filePath()[0] != QLatin1Char('/') : true;
921 #endif
922 }
923 
925 {
926  Q_D(const QFSFileEngine);
927  static const uint nobodyID = (uint) -2;
928 
929  if (d->doStat(QFileSystemMetaData::OwnerIds))
930  return d->metaData.ownerId(own);
931 
932  return nobodyID;
933 }
934 
936 {
937 #ifndef Q_OS_SYMBIAN
938  if (own == OwnerUser)
939  return QFileSystemEngine::resolveUserName(ownerId(own));
940  return QFileSystemEngine::resolveGroupName(ownerId(own));
941 #else
942  Q_UNUSED(own)
943  return QString();
944 #endif
945 }
946 
948 {
951  if (!QFileSystemEngine::setPermissions(d->fileEntry, QFile::Permissions(perms), error, 0)) {
952  setError(QFile::PermissionsError, error.toString());
953  return false;
954  }
955  return true;
956 }
957 
958 #ifdef Q_OS_SYMBIAN
960 {
962  bool ret = false;
963  TInt err = KErrNone;
964  if (d->symbianFile.SubSessionHandle()) {
965  TInt err = d->symbianFile.SetSize(size);
966  ret = (err == KErrNone);
967  if (ret && d->symbianFilePos > size)
968  d->symbianFilePos = size;
969  }
970  else if (d->fd != -1)
971  ret = QT_FTRUNCATE(d->fd, size) == 0;
972  else if (d->fh)
973  ret = QT_FTRUNCATE(QT_FILENO(d->fh), size) == 0;
974  else {
975  RFile tmp;
976  QString symbianFilename(d->fileEntry.nativeFilePath());
977  err = tmp.Open(qt_s60GetRFs(), qt_QString2TPtrC(symbianFilename), EFileWrite);
978  if (err == KErrNone)
979  {
980  err = tmp.SetSize(size);
981  tmp.Close();
982  }
983  ret = (err == KErrNone);
984  }
985  if (!ret) {
987  if (err)
989  else
991  setError(QFile::ResizeError, error.toString());
992  }
993  return ret;
994 }
995 #else
997 {
999  bool ret = false;
1000  if (d->fd != -1)
1001  ret = QT_FTRUNCATE(d->fd, size) == 0;
1002  else if (d->fh)
1003  ret = QT_FTRUNCATE(QT_FILENO(d->fh), size) == 0;
1004  else
1005  ret = QT_TRUNCATE(d->fileEntry.nativeFilePath().constData(), size) == 0;
1006  if (!ret)
1008  return ret;
1009 }
1010 #endif
1011 
1013 {
1014  Q_D(const QFSFileEngine);
1015 
1016  if (d->doStat(QFileSystemMetaData::Times))
1017  return d->metaData.fileTime(time);
1018 
1019  return QDateTime();
1020 }
1021 
1023 {
1024  Q_Q(QFSFileEngine);
1025  Q_UNUSED(flags);
1026  if (openMode == QIODevice::NotOpen) {
1027  q->setError(QFile::PermissionsError, qt_error_string(int(EACCES)));
1028  return 0;
1029  }
1030 
1031  if (offset < 0 || offset != qint64(QT_OFF_T(offset))
1032  || size < 0 || quint64(size) > quint64(size_t(-1))) {
1033  q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
1034  return 0;
1035  }
1036 
1037  // If we know the mapping will extend beyond EOF, fail early to avoid
1038  // undefined behavior. Otherwise, let mmap have its say.
1040  && (QT_OFF_T(size) > metaData.size() - QT_OFF_T(offset)))
1041  qWarning("QFSFileEngine::map: Mapping a file beyond its size is not portable");
1042 
1043  int access = 0;
1044  if (openMode & QIODevice::ReadOnly) access |= PROT_READ;
1045  if (openMode & QIODevice::WriteOnly) access |= PROT_WRITE;
1046 
1047 #if defined(Q_OS_INTEGRITY)
1048  int pageSize = sysconf(_SC_PAGESIZE);
1049 #else
1050  int pageSize = getpagesize();
1051 #endif
1052  int extra = offset % pageSize;
1053 
1054  if (quint64(size + extra) > quint64((size_t)-1)) {
1055  q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
1056  return 0;
1057  }
1058 
1059  size_t realSize = (size_t)size + extra;
1060  QT_OFF_T realOffset = QT_OFF_T(offset);
1061  realOffset &= ~(QT_OFF_T(pageSize - 1));
1062 
1063 #ifdef QT_SYMBIAN_USE_NATIVE_FILEMAP
1064  TInt nativeMapError = KErrNone;
1065  RFileMap mapping;
1066  TUint mode(EFileMapRemovableMedia);
1067  TUint64 nativeOffset = offset & ~(mapping.PageSizeInBytes() - 1);
1068 
1069  //If the file was opened for write or read/write, then open the map for read/write
1070  if (openMode & QIODevice::WriteOnly)
1071  mode |= EFileMapWrite;
1072  if (symbianFile.SubSessionHandle()) {
1073  nativeMapError = mapping.Open(symbianFile, nativeOffset, size, mode);
1074  } else {
1075  //map file by name if we don't have a native handle
1077  TUint filemode = EFileShareReadersOrWriters | EFileRead;
1078  if (openMode & QIODevice::WriteOnly)
1079  filemode |= EFileWrite;
1080  nativeMapError = mapping.Open(qt_s60GetRFs(), qt_QString2TPtrC(fn), filemode, nativeOffset, size, mode);
1081  }
1082  if (nativeMapError == KErrNone) {
1083  QScopedResource<RFileMap> ptr(mapping); //will call Close if adding to mapping throws an exception
1084  uchar *address = mapping.Base() + (offset - nativeOffset);
1085  maps[address] = mapping;
1086  ptr.take();
1087  return address;
1088  }
1089  QFile::FileError reportedError = QFile::UnspecifiedError;
1090  switch (nativeMapError) {
1091  case KErrAccessDenied:
1092  case KErrPermissionDenied:
1093  reportedError = QFile::PermissionsError;
1094  break;
1095  case KErrNoMemory:
1096  reportedError = QFile::ResourceError;
1097  break;
1098  }
1099  q->setError(reportedError, QSystemError(nativeMapError, QSystemError::NativeError).toString());
1100  return 0;
1101 #else
1102 #ifdef Q_OS_SYMBIAN
1103  //older phones & emulator don't support native mapping, so need to keep the open C way around for those.
1104  void *mapAddress;
1105  TRAPD(err, mapAddress = QT_MMAP((void*)0, realSize,
1106  access, MAP_SHARED, getMapHandle(), realOffset));
1107  if (err != KErrNone) {
1108  qWarning("OpenC bug: leave from mmap %d", err);
1109  mapAddress = MAP_FAILED;
1110  errno = EINVAL;
1111  }
1112 #else
1113  void *mapAddress = QT_MMAP((void*)0, realSize,
1114  access, MAP_SHARED, nativeHandle(), realOffset);
1115 #endif
1116  if (MAP_FAILED != mapAddress) {
1117  uchar *address = extra + static_cast<uchar*>(mapAddress);
1118  maps[address] = QPair<int,size_t>(extra, realSize);
1119  return address;
1120  }
1121 
1122  switch(errno) {
1123  case EBADF:
1124  q->setError(QFile::PermissionsError, qt_error_string(int(EACCES)));
1125  break;
1126  case ENFILE:
1127  case ENOMEM:
1128  q->setError(QFile::ResourceError, qt_error_string(int(errno)));
1129  break;
1130  case EINVAL:
1131  // size are out of bounds
1132  default:
1133  q->setError(QFile::UnspecifiedError, qt_error_string(int(errno)));
1134  break;
1135  }
1136  return 0;
1137 #endif
1138 }
1139 
1141 {
1142 #if !defined(Q_OS_INTEGRITY)
1143  Q_Q(QFSFileEngine);
1144  if (!maps.contains(ptr)) {
1145  q->setError(QFile::PermissionsError, qt_error_string(EACCES));
1146  return false;
1147  }
1148 
1149 #ifdef QT_SYMBIAN_USE_NATIVE_FILEMAP
1150  RFileMap mapping = maps.value(ptr);
1151  TInt err = mapping.Flush();
1152  mapping.Close();
1153  maps.remove(ptr);
1154  if (err) {
1156  return false;
1157  }
1158  return true;
1159 #else
1160  uchar *start = ptr - maps[ptr].first;
1161  size_t len = maps[ptr].second;
1162  if (-1 == munmap(start, len)) {
1164  return false;
1165  }
1166  maps.remove(ptr);
1167  return true;
1168 #endif
1169 #else
1170  return false;
1171 #endif
1172 }
1173 
1175 
1176 #endif // QT_NO_FSFILEENGINE
uchar * map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags)
static bool fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data, QFileSystemMetaData::MetaDataFlags what)
double d
Definition: qnumeric_p.h:62
static QString currentPath(const QString &path=QString())
For Unix, returns the current working directory for the file engine.
QString qt_error_string(int errorCode)
Definition: qglobal.cpp:2600
static bool setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error, QFileSystemMetaData *data=0)
int type
Definition: qmetatype.cpp:239
#define MAP_FAILED
bool isLetter() const
Returns true if the character is a letter (Letter_* categories); otherwise returns false...
Definition: qchar.cpp:653
bool isRelativePath() const
Reimplemented Function
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
static QString tempPath()
Returns the temporary path (i.
int remove(const Key &key)
Removes all the items that have the key from the hash.
Definition: qhash.h:784
const QChar at(int i) const
Returns the character at the given index position in the string.
Definition: qstring.h:698
bool rmdir(const QString &dirName, bool recurseParentDirectories) const
Reimplemented Function
bool copy(const QString &newName)
For windows, copy the file to file copyName.
FileFlags fileFlags(FileFlags type) const
Reimplemented Function
static QString resolveGroupName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
#define error(msg)
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
int length() const
Returns the number of characters in this string.
Definition: qstring.h:696
#define O_TRUNC
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition: qstring.cpp:3734
FileName
These values are used to request a file name in a particular format.
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
static bool setCurrentPath(const QString &path)
Sets the current path (e.
qint64 writeFdFh(const char *data, qint64 len)
The QString class provides a Unicode character string.
Definition: qstring.h:83
#define Q_D(Class)
Definition: qglobal.h:2482
#define O_CREAT
bool contains(const Key &key) const
Returns true if the hash contains an item with the key; otherwise returns false.
Definition: qhash.h:872
const T value(const Key &key) const
Returns the value associated with the key.
Definition: qhash.h:606
QIODevice::OpenMode openMode
#define Q_Q(Class)
Definition: qglobal.h:2483
static QFileSystemEntry currentPath()
NativePath nativeFilePath() const
bool rename(const QString &newName)
Reimplemented Function
unsigned char uchar
Definition: qglobal.h:994
static QString toString(Register *reg, int type, bool *ok=0)
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
QString owner(FileOwner) const
Reimplemented Function
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
static QFileSystemEntry absoluteName(const QFileSystemEntry &entry)
static bool removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents)
static bool renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
static QString resolveUserName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
unsigned __int64 quint64
Definition: qglobal.h:943
int access(const char *, int)
bool setPermissions(uint perms)
Reimplemented Function
static QString homePath()
Returns the home path of the current user.
const char * name
bool open(QIODevice::OpenMode openMode)
Reimplemented Function
Q_CORE_EXPORT void qWarning(const char *,...)
bool caseSensitive() const
Returns true for Windows, false for Unix.
static QFileInfoList drives()
For Windows, returns the list of drives in the file system as a list of QFileInfo objects...
static const char * data(const QByteArray &arr)
unsigned int uint
Definition: qglobal.h:996
qint64 nativeRead(char *data, qint64 maxlen)
QString fileName(FileName file) const
Reimplemented Function
QHash< uchar *, DWORD > maps
bool link(const QString &newName)
Creates a link from the file currently specified by fileName() to newName.
const T * ptr(const T &t)
bool hasFlags(MetaDataFlags flags) const
__int64 qint64
Definition: qglobal.h:942
qint64 nativeReadLine(char *data, qint64 maxlen)
bool doStat(QFileSystemMetaData::MetaDataFlags flags) const
static QFileSystemEntry getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data)
QFileSystemEntry fileEntry
FileTime
These are used by the fileTime() function.
static bool createDirectory(const QFileSystemEntry &entry, bool createParents)
static QString bundleName(const QFileSystemEntry &entry)
QFileSystemMetaData metaData
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
static bool setCurrentPath(const QFileSystemEntry &entry)
int fcntl(int, int,...)
static bool createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
#define QT_OPEN
Definition: qcore_unix_p.h:186
The QDateTime class provides date and time functions.
Definition: qdatetime.h:216
void clearFlags(MetaDataFlags flags=AllMetaDataFlags)
static bool removeFile(const QFileSystemEntry &entry, QSystemError &error)
static QMap< QByteArray, int > mapping
Definition: qaxserver.cpp:577
qint64 posFdFh() const
MetaDataFlags missingFlags(MetaDataFlags flags)
static QString rootPath()
Returns the root path.
bool nativeOpen(QIODevice::OpenMode openMode)
qint64 readLineFdFh(char *data, qint64 maxlen)
uint ownerId(FileOwner) const
In Unix, if stat() is successful, the uid is returned if own is the owner.
QString filePath() const
qint64 nativeWrite(const char *data, qint64 len)
QDateTime fileTime(FileTime time) const
Reimplemented Function
QString toString()
static bool copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
T take(const Key &key)
Removes the item with the key key from the map and returns the value associated with it...
Definition: qmap.h:692
bool remove()
Reimplemented Function
MemoryMapFlags
This enum describes special options that may be used by the map() function.
Definition: qfile.h:180
FileError
This enum describes the errors that may be returned by the error() function.
Definition: qfile.h:74
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:60
static int openModeToOpenFlags(QIODevice::OpenMode mode)
Returns the stdio open flags corresponding to a QIODevice::OpenMode.
static QByteArray openModeToFopenMode(QIODevice::OpenMode flags, const QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData)
Returns the stdlib open string corresponding to a QIODevice::OpenMode.
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
static QString fileName(const QString &fileUrl)
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
QString path() const
const QChar * constData() const
Returns a pointer to the data stored in the QString.
Definition: qstring.h:712
bool mkdir(const QString &dirName, bool createParentDirectories) const
Reimplemented Function
bool setSize(qint64 size)
Reimplemented Function
static bool setCloseOnExec(int fd)
Sets the file descriptor to close on exec.
int errno
static QFileSystemEntry canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
const ushort * utf16() const
Returns the QString as a &#39;\0\&#39;-terminated array of unsigned shorts.
Definition: qstring.cpp:5290
qint64 readFdFh(char *data, qint64 maxlen)
The QFSFileEngine class implements Qt&#39;s default file engine.
Definition: qfsfileengine.h:60
#define QT_CLOSE
Definition: qcore_unix_p.h:304