137 */ |
135 */ |
138 QString QFSFileEnginePrivate::canonicalized(const QString &path) |
136 QString QFSFileEnginePrivate::canonicalized(const QString &path) |
139 { |
137 { |
140 if (path.isEmpty()) |
138 if (path.isEmpty()) |
141 return path; |
139 return path; |
|
140 |
|
141 // FIXME let's see if this stuff works, then we might be able to remove some of the other code. |
|
142 #if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) |
|
143 if (path.size() == 1 && path.at(0) == QLatin1Char('/')) |
|
144 return path; |
|
145 #endif |
|
146 // Mac OS X 10.5.x doesn't support the realpath(X,0) extenstion we use here. |
|
147 #if defined(Q_OS_LINIX) || defined(Q_OS_SYMBIAN) |
|
148 char *ret = realpath(path.toLocal8Bit().constData(), (char*)0); |
|
149 if (ret) { |
|
150 QString canonicalPath = QDir::cleanPath(QString::fromLocal8Bit(ret)); |
|
151 free(ret); |
|
152 return canonicalPath; |
|
153 } |
|
154 #endif |
142 |
155 |
143 QFileInfo fi; |
156 QFileInfo fi; |
144 const QChar slash(QLatin1Char('/')); |
157 const QChar slash(QLatin1Char('/')); |
145 QString tmpPath = path; |
158 QString tmpPath = path; |
146 int separatorPos = 0; |
159 int separatorPos = 0; |
158 separatorPos = tmpPath.indexOf(slash, separatorPos + 1); |
171 separatorPos = tmpPath.indexOf(slash, separatorPos + 1); |
159 QString prefix = separatorPos == -1 ? tmpPath : tmpPath.left(separatorPos); |
172 QString prefix = separatorPos == -1 ? tmpPath : tmpPath.left(separatorPos); |
160 if ( |
173 if ( |
161 #ifdef Q_OS_SYMBIAN |
174 #ifdef Q_OS_SYMBIAN |
162 // Symbian doesn't support directory symlinks, so do not check for link unless we |
175 // Symbian doesn't support directory symlinks, so do not check for link unless we |
163 // are handling the last path element. This not only slightly improves performance, |
176 // are handling the last path element. This not only slightly improves performance, |
164 // but also saves us from lot of unnecessary platform security check failures |
177 // but also saves us from lot of unnecessary platform security check failures |
165 // when dealing with files under *:/private directories. |
178 // when dealing with files under *:/private directories. |
166 separatorPos == -1 && |
179 separatorPos == -1 && |
167 #endif |
180 #endif |
168 !nonSymlinks.contains(prefix)) { |
181 !nonSymlinks.contains(prefix)) { |
169 fi.setFile(prefix); |
182 fi.setFile(prefix); |
170 if (fi.isSymLink()) { |
183 if (fi.isSymLink()) { |
171 QString target = fi.symLinkTarget(); |
184 QString target = fi.symLinkTarget(); |
172 if (separatorPos != -1) { |
185 if (separatorPos != -1) { |
317 // Seek to the end when in Append mode. |
330 // Seek to the end when in Append mode. |
318 if (openMode & QIODevice::Append) { |
331 if (openMode & QIODevice::Append) { |
319 int ret; |
332 int ret; |
320 do { |
333 do { |
321 ret = QT_FSEEK(fh, 0, SEEK_END); |
334 ret = QT_FSEEK(fh, 0, SEEK_END); |
322 } while (ret == -1 && errno == EINTR); |
335 } while (ret != 0 && errno == EINTR); |
323 |
336 |
324 if (ret == -1) { |
337 if (ret != 0) { |
325 q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, |
338 q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, |
326 qt_error_string(int(errno))); |
339 qt_error_string(int(errno))); |
327 |
340 |
328 this->openMode = QIODevice::NotOpen; |
341 this->openMode = QIODevice::NotOpen; |
329 this->fh = 0; |
342 this->fh = 0; |
564 // fwrite are undefined if not called either in sequence, or if preceded |
577 // fwrite are undefined if not called either in sequence, or if preceded |
565 // with a call to fflush(). |
578 // with a call to fflush(). |
566 if (lastIOCommand != QFSFileEnginePrivate::IOFlushCommand && !q->flush()) |
579 if (lastIOCommand != QFSFileEnginePrivate::IOFlushCommand && !q->flush()) |
567 return false; |
580 return false; |
568 |
581 |
|
582 if (pos < 0 || pos != qint64(QT_OFF_T(pos))) |
|
583 return false; |
|
584 |
569 if (fh) { |
585 if (fh) { |
570 // Buffered stdlib mode. |
586 // Buffered stdlib mode. |
571 int ret; |
587 int ret; |
572 do { |
588 do { |
573 ret = QT_FSEEK(fh, QT_OFF_T(pos), SEEK_SET); |
589 ret = QT_FSEEK(fh, QT_OFF_T(pos), SEEK_SET); |
574 } while (ret == -1 && errno == EINTR); |
590 } while (ret != 0 && errno == EINTR); |
575 |
591 |
576 if (ret == -1) { |
592 if (ret != 0) { |
577 q->setError(QFile::ReadError, qt_error_string(int(errno))); |
593 q->setError(QFile::ReadError, qt_error_string(int(errno))); |
578 return false; |
594 return false; |
579 } |
595 } |
580 } else { |
596 } else { |
581 // Unbuffered stdio mode. |
597 // Unbuffered stdio mode. |
582 if (QT_LSEEK(fd, pos, SEEK_SET) == -1) { |
598 if (QT_LSEEK(fd, QT_OFF_T(pos), SEEK_SET) == -1) { |
583 qWarning() << "QFile::at: Cannot set file position" << pos; |
599 qWarning() << "QFile::at: Cannot set file position" << pos; |
584 q->setError(QFile::PositionError, qt_error_string(errno)); |
600 q->setError(QFile::PositionError, qt_error_string(errno)); |
585 return false; |
601 return false; |
586 } |
602 } |
587 } |
603 } |
620 */ |
636 */ |
621 qint64 QFSFileEnginePrivate::readFdFh(char *data, qint64 len) |
637 qint64 QFSFileEnginePrivate::readFdFh(char *data, qint64 len) |
622 { |
638 { |
623 Q_Q(QFSFileEngine); |
639 Q_Q(QFSFileEngine); |
624 |
640 |
625 // Buffered stdlib mode. |
641 if (len < 0 || len != qint64(size_t(len))) { |
|
642 q->setError(QFile::ReadError, qt_error_string(EINVAL)); |
|
643 return -1; |
|
644 } |
|
645 |
|
646 qint64 readBytes = 0; |
|
647 bool eof = false; |
|
648 |
626 if (fh) { |
649 if (fh) { |
627 qint64 readBytes = 0; |
650 // Buffered stdlib mode. |
628 qint64 read = 0; |
651 |
629 int retry = 0; |
652 size_t result; |
630 |
653 bool retry = true; |
631 // Read in blocks of 4k to avoid platform limitations (Windows |
|
632 // commonly bails out if you read or write too large blocks at once). |
|
633 qint64 bytesToRead; |
|
634 do { |
654 do { |
635 if (retry == 1) |
655 result = fread(data + readBytes, 1, size_t(len - readBytes), fh); |
636 retry = 2; |
656 eof = feof(fh); |
637 |
657 if (retry && eof && result == 0) { |
638 bytesToRead = qMin<qint64>(4096, len - read); |
658 // On Mac OS, this is needed, e.g., if a file was written to |
639 do { |
659 // through another stream since our last read. See test |
640 readBytes = fread(data + read, 1, size_t(bytesToRead), fh); |
660 // tst_QFile::appendAndRead |
641 } while (readBytes == 0 && !feof(fh) && errno == EINTR); |
661 QT_FSEEK(fh, QT_FTELL(fh), SEEK_SET); // re-sync stream. |
642 |
662 retry = false; |
643 if (readBytes > 0) { |
663 continue; |
644 read += readBytes; |
|
645 } else if (!retry && feof(fh)) { |
|
646 // Synchronize and try again (just once though). |
|
647 if (++retry == 1) |
|
648 QT_FSEEK(fh, QT_FTELL(fh), SEEK_SET); |
|
649 } |
664 } |
650 } while (retry == 1 || (readBytes == bytesToRead && read < len)); |
665 readBytes += result; |
651 |
666 } while (!eof && (result == 0 ? errno == EINTR : readBytes < len)); |
652 // Return the number of bytes read, or if nothing was read, return -1 |
667 |
653 // if an error occurred, or 0 if we detected EOF. |
668 } else if (fd != -1) { |
654 if (read == 0) { |
669 // Unbuffered stdio mode. |
655 q->setError(QFile::ReadError, qt_error_string(int(errno))); |
670 |
656 if (!feof(fh)) |
671 #ifdef Q_OS_WIN |
657 read = -1; |
|
658 } |
|
659 return read; |
|
660 } |
|
661 |
|
662 // Unbuffered stdio mode. |
|
663 qint64 ret = 0; |
|
664 if (len) { |
|
665 int result; |
672 int result; |
666 qint64 read = 0; |
673 #else |
667 errno = 0; |
674 ssize_t result; |
668 |
675 #endif |
669 // Read in blocks of 4k to avoid platform limitations (Windows |
|
670 // commonly bails out if you read or write too large blocks at once). |
|
671 do { |
676 do { |
672 qint64 bytesToRead = qMin<qint64>(4096, len - read); |
677 result = QT_READ(fd, data + readBytes, size_t(len - readBytes)); |
673 do { |
678 } while ((result == -1 && errno == EINTR) |
674 result = QT_READ(fd, data + read, int(bytesToRead)); |
679 || (result > 0 && (readBytes += result) < len)); |
675 } while (result == -1 && errno == EINTR); |
680 |
676 if (result > 0) |
681 eof = !(result == -1); |
677 read += result; |
682 } |
678 } while (result > 0 && read < len); |
683 |
679 |
684 if (!eof && readBytes == 0) { |
680 // Return the number of bytes read, or if nothing was read, return -1 |
685 readBytes = -1; |
681 // if an error occurred. |
686 q->setError(QFile::ReadError, qt_error_string(errno)); |
682 if (read > 0) { |
687 } |
683 ret += read; |
688 |
684 } else if (read == 0 && result < 0) { |
689 return readBytes; |
685 ret = -1; |
|
686 q->setError(QFile::ReadError, qt_error_string(errno)); |
|
687 } |
|
688 } |
|
689 return ret; |
|
690 } |
690 } |
691 |
691 |
692 /*! |
692 /*! |
693 \reimp |
693 \reimp |
694 */ |
694 */ |
764 \internal |
764 \internal |
765 */ |
765 */ |
766 qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len) |
766 qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len) |
767 { |
767 { |
768 Q_Q(QFSFileEngine); |
768 Q_Q(QFSFileEngine); |
769 qint64 result; |
769 |
770 qint64 written = 0; |
770 if (len < 0 || len != qint64(size_t(len))) { |
771 |
771 q->setError(QFile::WriteError, qt_error_string(EINVAL)); |
772 do { |
772 return -1; |
773 // Write blocks of 4k to avoid platform limitations (Windows commonly |
773 } |
774 // bails out if you read or write too large blocks at once). |
774 |
775 qint64 bytesToWrite = qMin<qint64>(4096, len - written); |
775 qint64 writtenBytes = 0; |
776 if (fh) { |
776 |
777 do { |
777 if (fh) { |
778 // Buffered stdlib mode. |
778 // Buffered stdlib mode. |
779 result = qint64(fwrite(data + written, 1, size_t(bytesToWrite), fh)); |
779 |
780 } while (result == 0 && errno == EINTR); |
780 size_t result; |
781 if (bytesToWrite > 0 && result == 0) |
781 do { |
782 result = -1; |
782 result = fwrite(data + writtenBytes, 1, size_t(len - writtenBytes), fh); |
783 } else { |
783 writtenBytes += result; |
784 do { |
784 } while (result == 0 ? errno == EINTR : writtenBytes < len); |
785 // Unbuffered stdio mode. |
785 |
786 result = QT_WRITE(fd, data + written, bytesToWrite); |
786 } else if (fd != -1) { |
787 } while (result == -1 && errno == EINTR); |
787 // Unbuffered stdio mode. |
788 } |
788 |
789 if (result > 0) |
789 #ifdef Q_OS_WIN |
790 written += qint64(result); |
790 int result; |
791 } while (written < len && result > 0); |
791 #else |
792 |
792 ssize_t result; |
793 // If we read anything, return that with success. Otherwise, set an error, |
793 #endif |
794 // and return the last return value. |
794 do { |
795 if (result > 0) |
795 result = QT_WRITE(fd, data + writtenBytes, size_t(len - writtenBytes)); |
796 return written; |
796 } while ((result == -1 && errno == EINTR) |
797 q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError, qt_error_string(errno)); |
797 || (result > 0 && (writtenBytes += result) < len)); |
798 return result; |
798 } |
|
799 |
|
800 if (len && writtenBytes == 0) { |
|
801 writtenBytes = -1; |
|
802 q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError, qt_error_string(errno)); |
|
803 } |
|
804 |
|
805 return writtenBytes; |
799 } |
806 } |
800 |
807 |
801 /*! |
808 /*! |
802 \internal |
809 \internal |
803 */ |
810 */ |
901 */ |
908 */ |
902 |
909 |
903 /*! \fn QString QFSFileEngine::currentPath(const QString &fileName) |
910 /*! \fn QString QFSFileEngine::currentPath(const QString &fileName) |
904 For Unix, returns the current working directory for the file |
911 For Unix, returns the current working directory for the file |
905 engine. |
912 engine. |
906 |
913 |
907 For Windows, returns the canonicalized form of the current path used |
914 For Windows, returns the canonicalized form of the current path used |
908 by the file engine for the drive specified by \a fileName. On |
915 by the file engine for the drive specified by \a fileName. On |
909 Windows, each drive has its own current directory, so a different |
916 Windows, each drive has its own current directory, so a different |
910 path is returned for file names that include different drive names |
917 path is returned for file names that include different drive names |
911 (e.g. A: or C:). |
918 (e.g. A: or C:). |