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