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