1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qtemporaryfile.h"
43 
44 #ifndef QT_NO_TEMPORARYFILE
45 
46 #include "qplatformdefs.h"
47 #include "private/qfile_p.h"
48 #include "private/qfsfileengine_p.h"
49 #include "private/qsystemerror_p.h"
50 #include "private/qfilesystemengine_p.h"
51 
52 #if defined(Q_OS_SYMBIAN)
53 #include "private/qcore_symbian_p.h"
54 #endif
55 
56 #if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN)
57 #include "private/qcore_unix_p.h"       // overrides QT_OPEN
58 #include <errno.h>
59 #endif
60 
61 #if defined(QT_BUILD_CORE_LIB)
62 #include "qcoreapplication.h"
63 #endif
64 
65 QT_BEGIN_NAMESPACE
66 
67 #if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
68 typedef ushort Char;
69 
Latin1Char(char ch)70 static inline Char Latin1Char(char ch)
71 {
72     return ushort(uchar(ch));
73 }
74 
75 # ifdef Q_OS_WIN
76 typedef HANDLE NativeFileHandle;
77 # else // Q_OS_SYMBIAN
78 #  ifdef  SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
79 typedef RFile64 NativeFileHandle;
80 #  else
81 typedef RFile NativeFileHandle;
82 #  endif
83 # endif
84 
85 #else // POSIX
86 typedef char Char;
87 typedef char Latin1Char;
88 typedef int NativeFileHandle;
89 #endif
90 
91 /*
92  * Copyright (c) 1987, 1993
93  *	The Regents of the University of California.  All rights reserved.
94  *
95  * Redistribution and use in source and binary forms, with or without
96  * modification, are permitted provided that the following conditions
97  * are met:
98  * 1. Redistributions of source code must retain the above copyright
99  *    notice, this list of conditions and the following disclaimer.
100  * 2. Redistributions in binary form must reproduce the above copyright
101  *    notice, this list of conditions and the following disclaimer in the
102  *    documentation and/or other materials provided with the distribution.
103  * 3. Neither the name of the University nor the names of its contributors
104  *    may be used to endorse or promote products derived from this software
105  *    without specific prior written permission.
106  *
107  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
108  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
109  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
110  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
111  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
112  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
113  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
114  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
115  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
116  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
117  * SUCH DAMAGE.
118  */
119 
120 /*!
121     \internal
122 
123     Generates a unique file path and returns a native handle to the open file.
124     \a path is used as a template when generating unique paths, \a pos
125     identifies the position of the first character that will be replaced in the
126     template and \a length the number of characters that may be substituted.
127 
128     Returns an open handle to the newly created file if successful, an invalid
129     handle otherwise. In both cases, the string in \a path will be changed and
130     contain the generated path name.
131 */
createFileFromTemplate(NativeFileHandle & file,QFileSystemEntry::NativePath & path,size_t pos,size_t length,QSystemError & error)132 static bool createFileFromTemplate(NativeFileHandle &file,
133         QFileSystemEntry::NativePath &path, size_t pos, size_t length,
134         QSystemError &error)
135 {
136     Q_ASSERT(length != 0);
137     Q_ASSERT(pos < size_t(path.length()));
138     Q_ASSERT(length <= size_t(path.length()) - pos);
139 
140     Char *const placeholderStart = (Char *)path.data() + pos;
141     Char *const placeholderEnd = placeholderStart + length;
142 
143     // Initialize placeholder with random chars + PID.
144     {
145         Char *rIter = placeholderEnd;
146 
147 #if defined(QT_BUILD_CORE_LIB)
148         quint64 pid = quint64(QCoreApplication::applicationPid());
149         do {
150             *--rIter = Latin1Char((pid % 10) + '0');
151             pid /= 10;
152         } while (rIter != placeholderStart && pid != 0);
153 #endif
154 
155         while (rIter != placeholderStart) {
156             char ch = char((qrand() & 0xffff) % (26 + 26));
157             if (ch < 26)
158                 *--rIter = Latin1Char(ch + 'A');
159             else
160                 *--rIter = Latin1Char(ch - 26 + 'a');
161         }
162     }
163 
164 #ifdef Q_OS_SYMBIAN
165     RFs& fs = qt_s60GetRFs();
166 #endif
167 
168     for (;;) {
169         // Atomically create file and obtain handle
170 #if defined(Q_OS_WIN)
171         file = CreateFile((const wchar_t *)path.constData(),
172                 GENERIC_READ | GENERIC_WRITE,
173                 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW,
174                 FILE_ATTRIBUTE_NORMAL, NULL);
175 
176         if (file != INVALID_HANDLE_VALUE)
177             return true;
178 
179         DWORD err = GetLastError();
180         if (err != ERROR_FILE_EXISTS) {
181             error = QSystemError(err, QSystemError::NativeError);
182             return false;
183         }
184 #elif defined(Q_OS_SYMBIAN)
185         TInt err = file.Create(fs, qt_QString2TPtrC(path),
186                 EFileRead | EFileWrite | EFileShareReadersOrWriters);
187 
188         if (err == KErrNone)
189             return true;
190 
191         if (err != KErrAlreadyExists) {
192             error = QSystemError(err, QSystemError::NativeError);
193             return false;
194         }
195 #else // POSIX
196         file = QT_OPEN(path.constData(),
197                 QT_OPEN_CREAT | O_EXCL | QT_OPEN_RDWR | QT_OPEN_LARGEFILE,
198                 0600);
199 
200         if (file != -1)
201             return true;
202 
203         int err = errno;
204         if (err != EEXIST) {
205             error = QSystemError(err, QSystemError::NativeError);
206             return false;
207         }
208 #endif
209 
210         /* tricky little algorwwithm for backward compatibility */
211         for (Char *iter = placeholderStart;;) {
212             // Character progression: [0-9] => 'a' ... 'z' => 'A' .. 'Z'
213             // String progression: "ZZaiC" => "aabiC"
214             switch (char(*iter)) {
215                 case 'Z':
216                     // Rollover, advance next character
217                     *iter = Latin1Char('a');
218                     if (++iter == placeholderEnd) {
219                         // Out of alternatives. Return file exists error, previously set.
220                         error = QSystemError(err, QSystemError::NativeError);
221                         return false;
222                     }
223 
224                     continue;
225 
226                 case '0': case '1': case '2': case '3': case '4':
227                 case '5': case '6': case '7': case '8': case '9':
228                     *iter = Latin1Char('a');
229                     break;
230 
231                 case 'z':
232                     // increment 'z' to 'A'
233                     *iter = Latin1Char('A');
234                     break;
235 
236                 default:
237                     ++*iter;
238                     break;
239             }
240             break;
241         }
242     }
243 
244     Q_ASSERT(false);
245 }
246 
247 //************* QTemporaryFileEngine
248 class QTemporaryFileEngine : public QFSFileEngine
249 {
250     Q_DECLARE_PRIVATE(QFSFileEngine)
251 public:
QTemporaryFileEngine(const QString & file,bool fileIsTemplate=true)252     QTemporaryFileEngine(const QString &file, bool fileIsTemplate = true)
253         : QFSFileEngine(), filePathIsTemplate(fileIsTemplate)
254     {
255         Q_D(QFSFileEngine);
256         d->fileEntry = QFileSystemEntry(file);
257 
258         if (!filePathIsTemplate)
259             QFSFileEngine::setFileName(file);
260     }
261 
262     ~QTemporaryFileEngine();
263 
264     bool isReallyOpen();
265     void setFileName(const QString &file);
266     void setFileTemplate(const QString &fileTemplate);
267 
268     bool open(QIODevice::OpenMode flags);
269     bool remove();
270     bool rename(const QString &newName);
271     bool close();
272 
273     bool filePathIsTemplate;
274 };
275 
~QTemporaryFileEngine()276 QTemporaryFileEngine::~QTemporaryFileEngine()
277 {
278     QFSFileEngine::close();
279 }
280 
isReallyOpen()281 bool QTemporaryFileEngine::isReallyOpen()
282 {
283     Q_D(QFSFileEngine);
284 
285     if (!((0 == d->fh) && (-1 == d->fd)
286 #if defined (Q_OS_SYMBIAN)
287                 && (0 == d->symbianFile.SubSessionHandle())
288 #endif
289 #if defined Q_OS_WIN
290                 && (INVALID_HANDLE_VALUE == d->fileHandle)
291 #endif
292             ))
293         return true;
294 
295     return false;
296 
297 }
298 
setFileName(const QString & file)299 void QTemporaryFileEngine::setFileName(const QString &file)
300 {
301     // Really close the file, so we don't leak
302     QFSFileEngine::close();
303     QFSFileEngine::setFileName(file);
304 }
305 
setFileTemplate(const QString & fileTemplate)306 void QTemporaryFileEngine::setFileTemplate(const QString &fileTemplate)
307 {
308     Q_D(QFSFileEngine);
309     if (filePathIsTemplate)
310         d->fileEntry = QFileSystemEntry(fileTemplate);
311 }
312 
open(QIODevice::OpenMode openMode)313 bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode)
314 {
315     Q_D(QFSFileEngine);
316     Q_ASSERT(!isReallyOpen());
317 
318     openMode |= QIODevice::ReadWrite;
319 
320     if (!filePathIsTemplate)
321         return QFSFileEngine::open(openMode);
322 
323     QString qfilename = d->fileEntry.filePath();
324 
325     // Ensure there is a placeholder mask
326     uint phPos = qfilename.length();
327     uint phLength = 0;
328 
329     while (phPos != 0) {
330         --phPos;
331 
332         if (qfilename[phPos] == QLatin1Char('X')) {
333             ++phLength;
334             continue;
335         }
336 
337         if (phLength >= 6
338                 || qfilename[phPos] == QLatin1Char('/')) {
339             ++phPos;
340             break;
341         }
342 
343         // start over
344         phLength = 0;
345     }
346 
347     if (phLength < 6)
348         qfilename.append(QLatin1String(".XXXXXX"));
349 
350     // "Nativify" :-)
351     QFileSystemEntry::NativePath filename = QFileSystemEngine::absoluteName(
352             QFileSystemEntry(qfilename, QFileSystemEntry::FromInternalPath()))
353         .nativeFilePath();
354 
355     // Find mask in native path
356     phPos = filename.length();
357     phLength = 0;
358     while (phPos != 0) {
359         --phPos;
360 
361         if (filename[phPos] == Latin1Char('X')) {
362             ++phLength;
363             continue;
364         }
365 
366         if (phLength >= 6) {
367             ++phPos;
368             break;
369         }
370 
371         // start over
372         phLength = 0;
373     }
374 
375     Q_ASSERT(phLength >= 6);
376 
377     QSystemError error;
378 #if defined(Q_OS_WIN)
379     NativeFileHandle &file = d->fileHandle;
380 #elif defined(Q_OS_SYMBIAN)
381     NativeFileHandle &file = d->symbianFile;
382 #else // POSIX
383     NativeFileHandle &file = d->fd;
384 #endif
385 
386     if (!createFileFromTemplate(file, filename, phPos, phLength, error)) {
387         setError(QFile::OpenError, error.toString());
388         return false;
389     }
390 
391     d->fileEntry = QFileSystemEntry(filename, QFileSystemEntry::FromNativePath());
392 
393 #if !defined(Q_OS_WIN)
394     d->closeFileHandle = true;
395 #endif
396 
397     filePathIsTemplate = false;
398 
399     d->openMode = openMode;
400     d->lastFlushFailed = false;
401     d->tried_stat = 0;
402 
403     return true;
404 }
405 
remove()406 bool QTemporaryFileEngine::remove()
407 {
408     Q_D(QFSFileEngine);
409     // Since the QTemporaryFileEngine::close() does not really close the file,
410     // we must explicitly call QFSFileEngine::close() before we remove it.
411     QFSFileEngine::close();
412     if (QFSFileEngine::remove()) {
413         d->fileEntry.clear();
414         return true;
415     }
416     return false;
417 }
418 
rename(const QString & newName)419 bool QTemporaryFileEngine::rename(const QString &newName)
420 {
421     QFSFileEngine::close();
422     return QFSFileEngine::rename(newName);
423 }
424 
close()425 bool QTemporaryFileEngine::close()
426 {
427     // Don't close the file, just seek to the front.
428     seek(0);
429     setError(QFile::UnspecifiedError, QString());
430     return true;
431 }
432 
433 //************* QTemporaryFilePrivate
434 class QTemporaryFilePrivate : public QFilePrivate
435 {
436     Q_DECLARE_PUBLIC(QTemporaryFile)
437 
438 protected:
439     QTemporaryFilePrivate();
440     ~QTemporaryFilePrivate();
441 
442     bool autoRemove;
443     QString templateName;
444 };
445 
QTemporaryFilePrivate()446 QTemporaryFilePrivate::QTemporaryFilePrivate() : autoRemove(true)
447 {
448 }
449 
~QTemporaryFilePrivate()450 QTemporaryFilePrivate::~QTemporaryFilePrivate()
451 {
452 }
453 
454 //************* QTemporaryFile
455 
456 /*!
457     \class QTemporaryFile
458     \reentrant
459     \brief The QTemporaryFile class is an I/O device that operates on temporary files.
460 
461     \ingroup io
462 
463 
464     QTemporaryFile is used to create unique temporary files safely.
465     The file itself is created by calling open(). The name of the
466     temporary file is guaranteed to be unique (i.e., you are
467     guaranteed to not overwrite an existing file), and the file will
468     subsequently be removed upon destruction of the QTemporaryFile
469     object. This is an important technique that avoids data
470     corruption for applications that store data in temporary files.
471     The file name is either auto-generated, or created based on a
472     template, which is passed to QTemporaryFile's constructor.
473 
474     Example:
475 
476     \snippet doc/src/snippets/code/src_corelib_io_qtemporaryfile.cpp 0
477 
478     Reopening a QTemporaryFile after calling close() is safe. For as long as
479     the QTemporaryFile object itself is not destroyed, the unique temporary
480     file will exist and be kept open internally by QTemporaryFile.
481 
482     The file name of the temporary file can be found by calling fileName().
483     Note that this is only defined after the file is first opened; the function
484     returns an empty string before this.
485 
486     A temporary file will have some static part of the name and some
487     part that is calculated to be unique. The default filename \c
488     qt_temp will be placed into the temporary path as returned by
489     QDir::tempPath(). If you specify your own filename, a relative
490     file path will not be placed in the temporary directory by
491     default, but be relative to the current working directory.
492 
493     Specified filenames can contain the following template \c XXXXXX
494     (six upper case "X" characters), which will be replaced by the
495     auto-generated portion of the filename. Note that the template is
496     case sensitive. If the template is not present in the filename,
497     QTemporaryFile appends the generated part to the filename given.
498 
499     \sa QDir::tempPath(), QFile
500 */
501 
502 #ifdef QT_NO_QOBJECT
QTemporaryFile()503 QTemporaryFile::QTemporaryFile()
504     : QFile(*new QTemporaryFilePrivate)
505 {
506     Q_D(QTemporaryFile);
507     d->templateName = QDir::tempPath() + QLatin1String("/qt_temp.XXXXXX");
508 }
509 
QTemporaryFile(const QString & templateName)510 QTemporaryFile::QTemporaryFile(const QString &templateName)
511     : QFile(*new QTemporaryFilePrivate)
512 {
513     Q_D(QTemporaryFile);
514     d->templateName = templateName;
515 }
516 
517 #else
518 /*!
519     Constructs a QTemporaryFile in QDir::tempPath(), using the file template
520     "qt_temp.XXXXXX". The file is stored in the system's temporary directory.
521 
522     \sa setFileTemplate(), QDir::tempPath()
523 */
QTemporaryFile()524 QTemporaryFile::QTemporaryFile()
525     : QFile(*new QTemporaryFilePrivate, 0)
526 {
527     Q_D(QTemporaryFile);
528     d->templateName = QDir::tempPath() + QLatin1String("/qt_temp.XXXXXX");
529 }
530 
531 /*!
532     Constructs a QTemporaryFile with a template filename of \a
533     templateName. Upon opening the temporary file this will be used to create
534     a unique filename.
535 
536     If the \a templateName does not contain XXXXXX it will automatically be
537     appended and used as the dynamic portion of the filename.
538 
539     If \a templateName is a relative path, the path will be relative to the
540     current working directory. You can use QDir::tempPath() to construct \a
541     templateName if you want use the system's temporary directory.
542 
543     \sa open(), fileTemplate()
544 */
QTemporaryFile(const QString & templateName)545 QTemporaryFile::QTemporaryFile(const QString &templateName)
546     : QFile(*new QTemporaryFilePrivate, 0)
547 {
548     Q_D(QTemporaryFile);
549     d->templateName = templateName;
550 }
551 
552 /*!
553     Constructs a QTemporaryFile (with the given \a parent) in
554     QDir::tempPath(), using the file template "qt_temp.XXXXXX".
555 
556     \sa setFileTemplate()
557 */
QTemporaryFile(QObject * parent)558 QTemporaryFile::QTemporaryFile(QObject *parent)
559     : QFile(*new QTemporaryFilePrivate, parent)
560 {
561     Q_D(QTemporaryFile);
562     d->templateName = QDir::tempPath() + QLatin1String("/qt_temp.XXXXXX");
563 }
564 
565 /*!
566     Constructs a QTemporaryFile with a template filename of \a
567     templateName and the specified \a parent.
568     Upon opening the temporary file this will be used to
569     create a unique filename.
570 
571     If the \a templateName does not contain XXXXXX it will automatically be
572     appended and used as the dynamic portion of the filename.
573 
574     If \a templateName is a relative path, the path will be relative to the
575     current working directory. You can use QDir::tempPath() to construct \a
576     templateName if you want use the system's temporary directory.
577 
578     \sa open(), fileTemplate()
579 */
QTemporaryFile(const QString & templateName,QObject * parent)580 QTemporaryFile::QTemporaryFile(const QString &templateName, QObject *parent)
581     : QFile(*new QTemporaryFilePrivate, parent)
582 {
583     Q_D(QTemporaryFile);
584     d->templateName = templateName;
585 }
586 #endif
587 
588 /*!
589     Destroys the temporary file object, the file is automatically
590     closed if necessary and if in auto remove mode it will
591     automatically delete the file.
592 
593     \sa autoRemove()
594 */
~QTemporaryFile()595 QTemporaryFile::~QTemporaryFile()
596 {
597     Q_D(QTemporaryFile);
598     close();
599     if (!d->fileName.isEmpty() && d->autoRemove)
600         remove();
601 }
602 
603 /*!
604   \fn bool QTemporaryFile::open()
605 
606   A QTemporaryFile will always be opened in QIODevice::ReadWrite mode,
607   this allows easy access to the data in the file. This function will
608   return true upon success and will set the fileName() to the unique
609   filename used.
610 
611   \sa fileName()
612 */
613 
614 /*!
615    Returns true if the QTemporaryFile is in auto remove
616    mode. Auto-remove mode will automatically delete the filename from
617    disk upon destruction. This makes it very easy to create your
618    QTemporaryFile object on the stack, fill it with data, read from
619    it, and finally on function return it will automatically clean up
620    after itself.
621 
622    Auto-remove is on by default.
623 
624    \sa setAutoRemove(), remove()
625 */
autoRemove() const626 bool QTemporaryFile::autoRemove() const
627 {
628     Q_D(const QTemporaryFile);
629     return d->autoRemove;
630 }
631 
632 /*!
633     Sets the QTemporaryFile into auto-remove mode if \a b is true.
634 
635     Auto-remove is on by default.
636 
637     \sa autoRemove(), remove()
638 */
setAutoRemove(bool b)639 void QTemporaryFile::setAutoRemove(bool b)
640 {
641     Q_D(QTemporaryFile);
642     d->autoRemove = b;
643 }
644 
645 /*!
646    Returns the complete unique filename backing the QTemporaryFile
647    object. This string is null before the QTemporaryFile is opened,
648    afterwards it will contain the fileTemplate() plus
649    additional characters to make it unique.
650 
651    \sa fileTemplate()
652 */
653 
fileName() const654 QString QTemporaryFile::fileName() const
655 {
656     Q_D(const QTemporaryFile);
657     if(d->fileName.isEmpty())
658         return QString();
659     return fileEngine()->fileName(QAbstractFileEngine::DefaultName);
660 }
661 
662 /*!
663   Returns the set file template. The default file template will be
664   called qt_temp and be placed in QDir::tempPath().
665 
666   \sa setFileTemplate()
667 */
fileTemplate() const668 QString QTemporaryFile::fileTemplate() const
669 {
670     Q_D(const QTemporaryFile);
671     return d->templateName;
672 }
673 
674 /*!
675    Sets the static portion of the file name to \a name. If the file
676    template ends in XXXXXX that will automatically be replaced with
677    the unique part of the filename, otherwise a filename will be
678    determined automatically based on the static portion specified.
679 
680     If \a name contains a relative file path, the path will be relative to the
681     current working directory. You can use QDir::tempPath() to construct \a
682     name if you want use the system's temporary directory.
683 
684    \sa fileTemplate()
685 */
setFileTemplate(const QString & name)686 void QTemporaryFile::setFileTemplate(const QString &name)
687 {
688     Q_D(QTemporaryFile);
689     d->templateName = name;
690     if (d->fileEngine)
691         static_cast<QTemporaryFileEngine*>(d->fileEngine)->setFileTemplate(name);
692 }
693 
694 /*!
695   \fn QTemporaryFile *QTemporaryFile::createLocalFile(const QString &fileName)
696   \overload
697 
698   Works on the given \a fileName rather than an existing QFile
699   object.
700 */
701 
702 
703 /*!
704   If \a file is not on a local disk, a temporary file is created
705   on a local disk, \a file is copied into the temporary local file,
706   and a pointer to the temporary local file is returned. If \a file
707   is already on a local disk, a copy is not created and 0 is returned.
708 */
createLocalFile(QFile & file)709 QTemporaryFile *QTemporaryFile::createLocalFile(QFile &file)
710 {
711     if (QAbstractFileEngine *engine = file.fileEngine()) {
712         if(engine->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)
713             return 0; //local already
714         //cache
715         bool wasOpen = file.isOpen();
716         qint64 old_off = 0;
717         if(wasOpen)
718             old_off = file.pos();
719         else
720             file.open(QIODevice::ReadOnly);
721         //dump data
722         QTemporaryFile *ret = new QTemporaryFile;
723         ret->open();
724         file.seek(0);
725         char buffer[1024];
726         while(true) {
727             qint64 len = file.read(buffer, 1024);
728             if(len < 1)
729                 break;
730             ret->write(buffer, len);
731         }
732         ret->seek(0);
733         //restore
734         if(wasOpen)
735             file.seek(old_off);
736         else
737             file.close();
738         //done
739         return ret;
740     }
741     return 0;
742 }
743 
744 /*!
745    \internal
746 */
747 
fileEngine() const748 QAbstractFileEngine *QTemporaryFile::fileEngine() const
749 {
750     Q_D(const QTemporaryFile);
751     if(!d->fileEngine) {
752         if (d->fileName.isEmpty())
753             d->fileEngine = new QTemporaryFileEngine(d->templateName);
754         else
755             d->fileEngine = new QTemporaryFileEngine(d->fileName, false);
756     }
757     return d->fileEngine;
758 }
759 
760 /*!
761    \reimp
762 
763     Creates a unique file name for the temporary file, and opens it.  You can
764     get the unique name later by calling fileName(). The file is guaranteed to
765     have been created by this function (i.e., it has never existed before).
766 */
open(OpenMode flags)767 bool QTemporaryFile::open(OpenMode flags)
768 {
769     Q_D(QTemporaryFile);
770     if (!d->fileName.isEmpty()) {
771         if (static_cast<QTemporaryFileEngine*>(fileEngine())->isReallyOpen()) {
772             setOpenMode(flags);
773             return true;
774         }
775     }
776 
777     if (QFile::open(flags)) {
778         d->fileName = d->fileEngine->fileName(QAbstractFileEngine::DefaultName);
779         return true;
780     }
781     return false;
782 }
783 
784 QT_END_NAMESPACE
785 
786 #endif // QT_NO_TEMPORARYFILE
787 
788 
789