Qt 4.8
qtemporaryfile.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 "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 
66 
67 #if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
68 typedef ushort Char;
69 
70 static inline Char Latin1Char(char ch)
71 {
72  return ushort(uchar(ch));
73 }
74 
75 # ifdef Q_OS_WIN
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 
136  QFileSystemEntry::NativePath &path, size_t pos, size_t length,
138 {
139  Q_ASSERT(length != 0);
140  Q_ASSERT(pos < size_t(path.length()));
141  Q_ASSERT(length <= size_t(path.length()) - pos);
142 
143  Char *const placeholderStart = (Char *)path.data() + pos;
144  Char *const placeholderEnd = placeholderStart + length;
145 
146  // Initialize placeholder with random chars + PID.
147  {
148  Char *rIter = placeholderEnd;
149 
150 #if defined(QT_BUILD_CORE_LIB)
152  do {
153  *--rIter = Latin1Char((pid % 10) + '0');
154  pid /= 10;
155  } while (rIter != placeholderStart && pid != 0);
156 #endif
157 
158  while (rIter != placeholderStart) {
159  char ch = char((qrand() & 0xffff) % (26 + 26));
160  if (ch < 26)
161  *--rIter = Latin1Char(ch + 'A');
162  else
163  *--rIter = Latin1Char(ch - 26 + 'a');
164  }
165  }
166 
167 #ifdef Q_OS_SYMBIAN
168  RFs& fs = qt_s60GetRFs();
169 #endif
170 
171  for (;;) {
172  // Atomically create file and obtain handle
173 #if defined(Q_OS_WIN)
174  file = CreateFile((const wchar_t *)path.constData(),
175  GENERIC_READ | GENERIC_WRITE,
176  FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW,
177  FILE_ATTRIBUTE_NORMAL, NULL);
178 
179  if (file != INVALID_HANDLE_VALUE)
180  return true;
181 
182  DWORD err = GetLastError();
183  if (err != ERROR_FILE_EXISTS) {
185  return false;
186  }
187 #elif defined(Q_OS_SYMBIAN)
188  TInt err = file.Create(fs, qt_QString2TPtrC(path),
189  EFileRead | EFileWrite | EFileShareReadersOrWriters);
190 
191  if (err == KErrNone)
192  return true;
193 
194  if (err != KErrAlreadyExists) {
196  return false;
197  }
198 #else // POSIX
199  file = QT_OPEN(path.constData(),
200  QT_OPEN_CREAT | O_EXCL | QT_OPEN_RDWR | QT_OPEN_LARGEFILE,
201  0600);
202 
203  if (file != -1)
204  return true;
205 
206  int err = errno;
207  if (err != EEXIST) {
209  return false;
210  }
211 #endif
212 
213  /* tricky little algorwwithm for backward compatibility */
214  for (Char *iter = placeholderStart;;) {
215  // Character progression: [0-9] => 'a' ... 'z' => 'A' .. 'Z'
216  // String progression: "ZZaiC" => "aabiC"
217  switch (char(*iter)) {
218  case 'Z':
219  // Rollover, advance next character
220  *iter = Latin1Char('a');
221  if (++iter == placeholderEnd) {
222  // Out of alternatives. Return file exists error, previously set.
224  return false;
225  }
226 
227  continue;
228 
229  case '0': case '1': case '2': case '3': case '4':
230  case '5': case '6': case '7': case '8': case '9':
231  *iter = Latin1Char('a');
232  break;
233 
234  case 'z':
235  // increment 'z' to 'A'
236  *iter = Latin1Char('A');
237  break;
238 
239  default:
240  ++*iter;
241  break;
242  }
243  break;
244  }
245  }
246 
247  Q_ASSERT(false);
248 }
249 
250 //************* QTemporaryFileEngine
252 {
254 public:
255  QTemporaryFileEngine(const QString &file, bool fileIsTemplate = true)
256  : QFSFileEngine(), filePathIsTemplate(fileIsTemplate)
257  {
259  d->fileEntry = QFileSystemEntry(file);
260 
261  if (!filePathIsTemplate)
263  }
264 
266 
267  bool isReallyOpen();
268  void setFileName(const QString &file);
269  void setFileTemplate(const QString &fileTemplate);
270 
271  bool open(QIODevice::OpenMode flags);
272  bool remove();
273  bool rename(const QString &newName);
274  bool close();
275 
277 };
278 
280 {
282 }
283 
285 {
287 
288  if (!((0 == d->fh) && (-1 == d->fd)
289 #if defined (Q_OS_SYMBIAN)
290  && (0 == d->symbianFile.SubSessionHandle())
291 #endif
292 #if defined Q_OS_WIN
293  && (INVALID_HANDLE_VALUE == d->fileHandle)
294 #endif
295  ))
296  return true;
297 
298  return false;
299 
300 }
301 
303 {
304  // Really close the file, so we don't leak
307 }
308 
310 {
312  if (filePathIsTemplate)
313  d->fileEntry = QFileSystemEntry(fileTemplate);
314 }
315 
316 bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode)
317 {
320 
321  openMode |= QIODevice::ReadWrite;
322 
323  if (!filePathIsTemplate)
324  return QFSFileEngine::open(openMode);
325 
326  QString qfilename = d->fileEntry.filePath();
327 
328  // Ensure there is a placeholder mask
329  uint phPos = qfilename.length();
330  uint phLength = 0;
331 
332  while (phPos != 0) {
333  --phPos;
334 
335  if (qfilename[phPos] == QLatin1Char('X')) {
336  ++phLength;
337  continue;
338  }
339 
340  if (phLength >= 6
341  || qfilename[phPos] == QLatin1Char('/')) {
342  ++phPos;
343  break;
344  }
345 
346  // start over
347  phLength = 0;
348  }
349 
350  if (phLength < 6)
351  qfilename.append(QLatin1String(".XXXXXX"));
352 
353  // "Nativify" :-)
356  .nativeFilePath();
357 
358  // Find mask in native path
359  phPos = filename.length();
360  phLength = 0;
361  while (phPos != 0) {
362  --phPos;
363 
364  if (filename[phPos] == Latin1Char('X')) {
365  ++phLength;
366  continue;
367  }
368 
369  if (phLength >= 6) {
370  ++phPos;
371  break;
372  }
373 
374  // start over
375  phLength = 0;
376  }
377 
378  Q_ASSERT(phLength >= 6);
379 
381 #if defined(Q_OS_WIN)
382  NativeFileHandle &file = d->fileHandle;
383 #elif defined(Q_OS_SYMBIAN)
384  NativeFileHandle &file = d->symbianFile;
385 #else // POSIX
386  NativeFileHandle &file = d->fd;
387 #endif
388 
389  if (!createFileFromTemplate(file, filename, phPos, phLength, error)) {
391  return false;
392  }
393 
394  d->fileEntry = QFileSystemEntry(filename, QFileSystemEntry::FromNativePath());
395 
396 #if !defined(Q_OS_WIN)
397  d->closeFileHandle = true;
398 #endif
399 
400  filePathIsTemplate = false;
401 
402  d->openMode = openMode;
403  d->lastFlushFailed = false;
404  d->tried_stat = 0;
405 
406  return true;
407 }
408 
410 {
412  // Since the QTemporaryFileEngine::close() does not really close the file,
413  // we must explicitly call QFSFileEngine::close() before we remove it.
415  if (QFSFileEngine::remove()) {
416  d->fileEntry.clear();
417  return true;
418  }
419  return false;
420 }
421 
423 {
425  return QFSFileEngine::rename(newName);
426 }
427 
429 {
430  // Don't close the file, just seek to the front.
431  seek(0);
433  return true;
434 }
435 
436 //************* QTemporaryFilePrivate
438 {
440 
441 protected:
444 
447 };
448 
450 {
451 }
452 
454 {
455 }
456 
457 //************* QTemporaryFile
458 
508 #ifdef QT_NO_QOBJECT
511 {
513  d->templateName = QDir::tempPath() + QLatin1String("/qt_temp.XXXXXX");
514 }
515 
518 {
520  d->templateName = templateName;
521 }
522 
523 #else
524 
531  : QFile(*new QTemporaryFilePrivate, 0)
532 {
534  d->templateName = QDir::tempPath() + QLatin1String("/qt_temp.XXXXXX");
535 }
536 
552  : QFile(*new QTemporaryFilePrivate, 0)
553 {
555  d->templateName = templateName;
556 }
557 
565  : QFile(*new QTemporaryFilePrivate, parent)
566 {
568  d->templateName = QDir::tempPath() + QLatin1String("/qt_temp.XXXXXX");
569 }
570 
587  : QFile(*new QTemporaryFilePrivate, parent)
588 {
590  d->templateName = templateName;
591 }
592 #endif
593 
602 {
604  close();
605  if (!d->fileName.isEmpty() && d->autoRemove)
606  remove();
607 }
608 
636 {
637  Q_D(const QTemporaryFile);
638  return d->autoRemove;
639 }
640 
649 {
651  d->autoRemove = b;
652 }
653 
664 {
665  Q_D(const QTemporaryFile);
666  if(d->fileName.isEmpty())
667  return QString();
669 }
670 
678 {
679  Q_D(const QTemporaryFile);
680  return d->templateName;
681 }
682 
696 {
698  d->templateName = name;
699  if (d->fileEngine)
700  static_cast<QTemporaryFileEngine*>(d->fileEngine)->setFileTemplate(name);
701 }
702 
719 {
720  if (QAbstractFileEngine *engine = file.fileEngine()) {
722  return 0; //local already
723  //cache
724  bool wasOpen = file.isOpen();
725  qint64 old_off = 0;
726  if(wasOpen)
727  old_off = file.pos();
728  else
730  //dump data
731  QTemporaryFile *ret = new QTemporaryFile;
732  ret->open();
733  file.seek(0);
734  char buffer[1024];
735  while(true) {
736  qint64 len = file.read(buffer, 1024);
737  if(len < 1)
738  break;
739  ret->write(buffer, len);
740  }
741  ret->seek(0);
742  //restore
743  if(wasOpen)
744  file.seek(old_off);
745  else
746  file.close();
747  //done
748  return ret;
749  }
750  return 0;
751 }
752 
758 {
759  Q_D(const QTemporaryFile);
760  if(!d->fileEngine) {
761  if (d->fileName.isEmpty())
762  d->fileEngine = new QTemporaryFileEngine(d->templateName);
763  else
764  d->fileEngine = new QTemporaryFileEngine(d->fileName, false);
765  }
766  return d->fileEngine;
767 }
768 
779 bool QTemporaryFile::open(OpenMode flags)
780 {
782  if (!d->fileName.isEmpty()) {
783  if (static_cast<QTemporaryFileEngine*>(fileEngine())->isReallyOpen()) {
784  setOpenMode(flags);
785  return true;
786  }
787  }
788 
789  if (QFile::open(flags)) {
790  d->fileName = d->fileEngine->fileName(QAbstractFileEngine::DefaultName);
791  return true;
792  }
793  return false;
794 }
795 
797 
798 #endif // QT_NO_TEMPORARYFILE
799 
800 
void setError(QFile::FileError error, const QString &str)
Sets the error type to error, and the error string to errorString.
double d
Definition: qnumeric_p.h:62
QTemporaryFileEngine(const QString &file, bool fileIsTemplate=true)
void setAutoRemove(bool b)
Sets the QTemporaryFile into auto-remove mode if b is true.
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
static bool createFileFromTemplate(NativeFileHandle &file, QFileSystemEntry::NativePath &path, size_t pos, size_t length, QSystemError &error)
Generates a unique file path and returns a native handle to the open file.
void setOpenMode(OpenMode openMode)
Sets the OpenMode of the device to openMode.
Definition: qiodevice.cpp:477
virtual QString fileName(FileName file=DefaultName) const
Return the file engine&#39;s current file name in the format specified by file.
bool open(OpenMode flags)
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition: qfile.cpp:1064
static Char Latin1Char(char ch)
static QTemporaryFile * createLocalFile(const QString &fileName)
This is an overloaded member function, provided for convenience. It differs from the above function o...
#define error(msg)
int length() const
Returns the number of characters in this string.
Definition: qstring.h:696
The QTemporaryFile class is an I/O device that operates on temporary files.
virtual QAbstractFileEngine * fileEngine() const
Returns the QIOEngine for this QFile object.
Definition: qfile.cpp:1965
bool open()
A QTemporaryFile will always be opened in QIODevice::ReadWrite mode, this allows easy access to the d...
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
~QTemporaryFile()
Destroys the temporary file object, the file is automatically closed if necessary and if in auto remo...
The QString class provides a Unicode character string.
Definition: qstring.h:83
Q_CORE_EXPORT int qrand()
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
#define Q_D(Class)
Definition: qglobal.h:2482
bool rename(const QString &newName)
Reimplemented Function
QChar * data()
Returns a pointer to the data stored in the QString.
Definition: qstring.h:710
void setFileName(const QString &file)
Reimplemented Function
NativePath nativeFilePath() const
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read...
Definition: qiodevice.cpp:791
bool rename(const QString &newName)
Reimplemented Function
void setFileName(const QString &file)
Reimplemented Function
unsigned char uchar
Definition: qglobal.h:994
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
static QFileSystemEntry absoluteName(const QFileSystemEntry &entry)
bool isOpen() const
Returns true if the device is open; otherwise returns false.
Definition: qiodevice.cpp:530
void setFileTemplate(const QString &fileTemplate)
unsigned __int64 quint64
Definition: qglobal.h:943
const char * name
bool open(QIODevice::OpenMode openMode)
Reimplemented Function
The QAbstractFileEngine class provides an abstraction for accessing the filesystem.
static qint64 applicationPid()
Returns the current process ID for the application.
bool seek(qint64)
Reimplemented Function
unsigned int uint
Definition: qglobal.h:996
QFile::FileError error() const
Returns the QFile::FileError that resulted from the last failed operation.
qint64 pos() const
Reimplemented Function
Definition: qfile.cpp:1720
ushort Char
__int64 qint64
Definition: qglobal.h:942
void * HANDLE
Definition: qnamespace.h:1671
bool close()
Reimplemented Function
static QString tempPath()
Returns the absolute path of the system&#39;s temporary directory.
Definition: qdir.cpp:1987
#define Q_DECLARE_PUBLIC(Class)
Definition: qglobal.h:2477
#define QT_OPEN
Definition: qcore_unix_p.h:186
QString & append(QChar c)
Definition: qstring.cpp:1777
QString fileTemplate() const
Returns the set file template.
bool open(QIODevice::OpenMode flags)
Reimplemented Function
The QFile class provides an interface for reading from and writing to files.
Definition: qfile.h:65
unsigned short ushort
Definition: qglobal.h:995
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
QString fileName() const
Returns the complete unique filename backing the QTemporaryFile object.
bool autoRemove() const
Returns true if the QTemporaryFile is in auto remove mode.
#define Q_OS_WIN
Definition: qglobal.h:270
virtual QAbstractFileEngine * fileEngine() const
QString toString()
QTemporaryFile()
Constructs a QTemporaryFile in QDir::tempPath(), using the file template "qt_temp.XXXXXX".
HANDLE NativeFileHandle
bool remove()
Reimplemented Function
bool remove()
Reimplemented Function
#define Q_DECLARE_PRIVATE(Class)
Definition: qglobal.h:2467
void setFileTemplate(const QString &name)
Sets the static portion of the file name to name.
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
Definition: qiodevice.cpp:1342
virtual void close()
Calls QFile::flush() and closes the file.
Definition: qfile.cpp:1680
bool seek(qint64 offset)
For random-access devices, this function sets the current position to pos, returning true on success...
Definition: qfile.cpp:1784
bool close()
Reimplemented Function
#define O_EXCL
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
const QChar * constData() const
Returns a pointer to the data stored in the QString.
Definition: qstring.h:712
int errno
The QFSFileEngine class implements Qt&#39;s default file engine.
Definition: qfsfileengine.h:60