|
Packit |
1c1d7e |
/****************************************************************************
|
|
Packit |
1c1d7e |
**
|
|
Packit |
1c1d7e |
**
|
|
Packit |
1c1d7e |
** Implementation of QFileInfo class
|
|
Packit |
1c1d7e |
**
|
|
Packit |
1c1d7e |
** Created : 950628
|
|
Packit |
1c1d7e |
**
|
|
Packit |
1c1d7e |
** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
|
|
Packit |
1c1d7e |
**
|
|
Packit |
1c1d7e |
** This file is part of the tools module of the Qt GUI Toolkit.
|
|
Packit |
1c1d7e |
**
|
|
Packit |
1c1d7e |
** This file may be distributed under the terms of the Q Public License
|
|
Packit |
1c1d7e |
** as defined by Trolltech AS of Norway and appearing in the file
|
|
Packit |
1c1d7e |
** LICENSE.QPL included in the packaging of this file.
|
|
Packit |
1c1d7e |
**
|
|
Packit |
1c1d7e |
** This file may be distributed and/or modified under the terms of the
|
|
Packit |
1c1d7e |
** GNU General Public License version 2 as published by the Free Software
|
|
Packit |
1c1d7e |
** Foundation and appearing in the file LICENSE.GPL included in the
|
|
Packit |
1c1d7e |
** packaging of this file.
|
|
Packit |
1c1d7e |
**
|
|
Packit |
1c1d7e |
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
|
|
Packit |
1c1d7e |
** licenses for Unix/X11 or for Qt/Embedded may use this file in accordance
|
|
Packit |
1c1d7e |
** with the Qt Commercial License Agreement provided with the Software.
|
|
Packit |
1c1d7e |
**
|
|
Packit |
1c1d7e |
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
|
Packit |
1c1d7e |
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
Packit |
1c1d7e |
**
|
|
Packit |
1c1d7e |
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
|
|
Packit |
1c1d7e |
** information about Qt Commercial License Agreements.
|
|
Packit |
1c1d7e |
** See http://www.trolltech.com/qpl/ for QPL licensing information.
|
|
Packit |
1c1d7e |
** See http://www.trolltech.com/gpl/ for GPL licensing information.
|
|
Packit |
1c1d7e |
**
|
|
Packit |
1c1d7e |
** Contact info@trolltech.com if any conditions of this licensing are
|
|
Packit |
1c1d7e |
** not clear to you.
|
|
Packit |
1c1d7e |
**
|
|
Packit |
1c1d7e |
**********************************************************************/
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
#include "qglobal.h"
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
#include "qfile.h"
|
|
Packit |
1c1d7e |
#include "qfiledefs_p.h"
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
#if (defined(_OS_MAC_) && (!defined(_OS_UNIX_))) || defined(_OS_MSDOS_) || defined(_OS_WIN32_) || defined(_OS_OS2_) || defined(_OS_CYGWIN_)
|
|
Packit |
1c1d7e |
# define HAS_TEXT_FILEMODE // has translate/text filemode
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
#if defined(O_NONBLOCK)
|
|
Packit |
1c1d7e |
# define HAS_ASYNC_FILEMODE
|
|
Packit |
1c1d7e |
# define OPEN_ASYNC O_NONBLOCK
|
|
Packit |
1c1d7e |
#elif defined(O_NDELAY)
|
|
Packit |
1c1d7e |
# define HAS_ASYNC_FILEMODE
|
|
Packit |
1c1d7e |
# define OPEN_ASYNC O_NDELAY
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
bool qt_file_access( const QString& fn, int t )
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
if ( fn.isEmpty() )
|
|
Packit |
1c1d7e |
return FALSE;
|
|
Packit |
1c1d7e |
return ACCESS( QFile::encodeName(fn), t ) == 0;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
/*!
|
|
Packit |
1c1d7e |
Removes the file \a fileName.
|
|
Packit |
1c1d7e |
Returns TRUE if successful, otherwise FALSE.
|
|
Packit |
1c1d7e |
*/
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
bool QFile::remove( const QString &fileName )
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
if ( fileName.isEmpty() ) {
|
|
Packit |
1c1d7e |
#if defined(CHECK_NULL)
|
|
Packit |
1c1d7e |
qWarning( "QFile::remove: Empty or null file name" );
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
return FALSE;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
return unlink( QFile::encodeName(fileName) ) == 0;
|
|
Packit |
1c1d7e |
// unlink more common in UNIX
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
#if defined(O_NONBLOCK)
|
|
Packit |
1c1d7e |
# define HAS_ASYNC_FILEMODE
|
|
Packit |
1c1d7e |
# define OPEN_ASYNC O_NONBLOCK
|
|
Packit |
1c1d7e |
#elif defined(O_NDELAY)
|
|
Packit |
1c1d7e |
# define HAS_ASYNC_FILEMODE
|
|
Packit |
1c1d7e |
# define OPEN_ASYNC O_NDELAY
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
/*!
|
|
Packit |
1c1d7e |
Opens the file specified by the file name currently set, using the mode \e m.
|
|
Packit |
1c1d7e |
Returns TRUE if successful, otherwise FALSE.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
The mode parameter \e m must be a combination of the following flags:
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
\c IO_Raw specified raw (non-buffered) file access.
|
|
Packit |
1c1d7e |
\c IO_ReadOnly opens the file in read-only mode.
|
|
Packit |
1c1d7e |
\c IO_WriteOnly opens the file in write-only mode (and truncates).
|
|
Packit |
1c1d7e |
\c IO_ReadWrite opens the file in read/write mode, equivalent to
|
|
Packit |
1c1d7e |
\c (IO_ReadOnly|IO_WriteOnly).
|
|
Packit |
1c1d7e |
\c IO_Append opens the file in append mode. This mode is very useful
|
|
Packit |
1c1d7e |
when you want to write something to a log file. The file index is set to
|
|
Packit |
1c1d7e |
the end of the file. Note that the result is undefined if you position the
|
|
Packit |
1c1d7e |
file index manually using at() in append mode.
|
|
Packit |
1c1d7e |
\c IO_Truncate truncates the file.
|
|
Packit |
1c1d7e |
\c IO_Translate enables carriage returns and linefeed translation
|
|
Packit |
1c1d7e |
for text files under MS-DOS, Windows and OS/2.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
The raw access mode is best when I/O is block-operated using 4kB block size
|
|
Packit |
1c1d7e |
or greater. Buffered access works better when reading small portions of
|
|
Packit |
1c1d7e |
data at a time.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
Important: When working with buffered files, data may
|
|
Packit |
1c1d7e |
not be written to the file at once. Call \link flush() flush\endlink
|
|
Packit |
1c1d7e |
to make sure the data is really written.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
\warning We have experienced problems with some C libraries when a buffered
|
|
Packit |
1c1d7e |
file is opened for both reading and writing. If a read operation takes place
|
|
Packit |
1c1d7e |
immediately after a write operation, the read buffer contains garbage data.
|
|
Packit |
1c1d7e |
Worse, the same garbage is written to the file. Calling flush() before
|
|
Packit |
1c1d7e |
readBlock() solved this problem.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
If the file does not exist and \c IO_WriteOnly or \c IO_ReadWrite is
|
|
Packit |
1c1d7e |
specified, it is created.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
Example:
|
|
Packit |
1c1d7e |
\code
|
|
Packit |
1c1d7e |
QFile f1( "/tmp/data.bin" );
|
|
Packit |
1c1d7e |
QFile f2( "readme.txt" );
|
|
Packit |
1c1d7e |
f1.open( IO_Raw | IO_ReadWrite | IO_Append );
|
|
Packit |
1c1d7e |
f2.open( IO_ReadOnly | IO_Translate );
|
|
Packit |
1c1d7e |
\endcode
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
\sa name(), close(), isOpen(), flush()
|
|
Packit |
1c1d7e |
*/
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
bool QFile::open( int m )
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
if ( isOpen() ) { // file already open
|
|
Packit |
1c1d7e |
#if defined(CHECK_STATE)
|
|
Packit |
1c1d7e |
qWarning( "QFile::open: File already open" );
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
return FALSE;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
if ( fn.isNull() ) { // no file name defined
|
|
Packit |
1c1d7e |
#if defined(CHECK_NULL)
|
|
Packit |
1c1d7e |
qWarning( "QFile::open: No file name specified" );
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
return FALSE;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
init(); // reset params
|
|
Packit |
1c1d7e |
setMode( m );
|
|
Packit |
1c1d7e |
if ( !(isReadable() || isWritable()) ) {
|
|
Packit |
1c1d7e |
#if defined(CHECK_RANGE)
|
|
Packit |
1c1d7e |
qWarning( "QFile::open: File access not specified" );
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
return FALSE;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
bool ok = TRUE;
|
|
Packit |
1c1d7e |
STATBUF st;
|
|
Packit |
1c1d7e |
if ( isRaw() ) { // raw file I/O
|
|
Packit |
1c1d7e |
int oflags = OPEN_RDONLY;
|
|
Packit |
1c1d7e |
if ( isReadable() && isWritable() )
|
|
Packit |
1c1d7e |
oflags = OPEN_RDWR;
|
|
Packit |
1c1d7e |
else if ( isWritable() )
|
|
Packit |
1c1d7e |
oflags = OPEN_WRONLY;
|
|
Packit |
1c1d7e |
if ( flags() & IO_Append ) { // append to end of file?
|
|
Packit |
1c1d7e |
if ( flags() & IO_Truncate )
|
|
Packit |
1c1d7e |
oflags |= (OPEN_CREAT | OPEN_TRUNC);
|
|
Packit |
1c1d7e |
else
|
|
Packit |
1c1d7e |
oflags |= (OPEN_APPEND | OPEN_CREAT);
|
|
Packit |
1c1d7e |
setFlags( flags() | IO_WriteOnly ); // append implies write
|
|
Packit |
1c1d7e |
} else if ( isWritable() ) { // create/trunc if writable
|
|
Packit |
1c1d7e |
if ( flags() & IO_Truncate )
|
|
Packit |
1c1d7e |
oflags |= (OPEN_CREAT | OPEN_TRUNC);
|
|
Packit |
1c1d7e |
else
|
|
Packit |
1c1d7e |
oflags |= OPEN_CREAT;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
#if defined(HAS_TEXT_FILEMODE)
|
|
Packit |
1c1d7e |
if ( isTranslated() )
|
|
Packit |
1c1d7e |
#ifdef __CYGWIN__
|
|
Packit |
1c1d7e |
/* Do nothing, allowing the Cygwin mount mode to take effect. */;
|
|
Packit |
1c1d7e |
#else
|
|
Packit |
1c1d7e |
oflags |= OPEN_TEXT;
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
else
|
|
Packit |
1c1d7e |
oflags |= OPEN_BINARY;
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
#if defined(HAS_ASYNC_FILEMODE)
|
|
Packit |
1c1d7e |
if ( isAsynchronous() )
|
|
Packit |
1c1d7e |
oflags |= OPEN_ASYNC;
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
fd = OPEN( QFile::encodeName(fn), oflags, 0666 );
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
if ( fd != -1 ) { // open successful
|
|
Packit |
1c1d7e |
FSTAT( fd, &st ); // get the stat for later usage
|
|
Packit |
1c1d7e |
} else {
|
|
Packit |
1c1d7e |
ok = FALSE;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
} else { // buffered file I/O
|
|
Packit |
1c1d7e |
QCString perm;
|
|
Packit |
1c1d7e |
char perm2[4];
|
|
Packit |
1c1d7e |
bool try_create = FALSE;
|
|
Packit |
1c1d7e |
if ( flags() & IO_Append ) { // append to end of file?
|
|
Packit |
1c1d7e |
setFlags( flags() | IO_WriteOnly ); // append implies write
|
|
Packit |
1c1d7e |
perm = isReadable() ? "a+" : "a";
|
|
Packit |
1c1d7e |
} else {
|
|
Packit |
1c1d7e |
if ( isReadWrite() ) {
|
|
Packit |
1c1d7e |
if ( flags() & IO_Truncate ) {
|
|
Packit |
1c1d7e |
perm = "w+";
|
|
Packit |
1c1d7e |
} else {
|
|
Packit |
1c1d7e |
perm = "r+";
|
|
Packit |
1c1d7e |
try_create = TRUE; // try to create if not exists
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
} else if ( isReadable() ) {
|
|
Packit |
1c1d7e |
perm = "r";
|
|
Packit |
1c1d7e |
} else if ( isWritable() ) {
|
|
Packit |
1c1d7e |
perm = "w";
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
qstrcpy( perm2, perm );
|
|
Packit |
1c1d7e |
#if defined(HAS_TEXT_FILEMODE)
|
|
Packit |
1c1d7e |
if ( isTranslated() )
|
|
Packit |
1c1d7e |
#ifdef __CYGWIN__
|
|
Packit |
1c1d7e |
/* Do nothing, allowing the Cygwin mount mode to take effect. */;
|
|
Packit |
1c1d7e |
#else
|
|
Packit |
1c1d7e |
strcat( perm2, "t" );
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
else
|
|
Packit |
1c1d7e |
strcat( perm2, "b" );
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
while (1) { // At most twice
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
fh = fopen( QFile::encodeName(fn), perm2 );
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
if ( !fh && try_create ) {
|
|
Packit |
1c1d7e |
perm2[0] = 'w'; // try "w+" instead of "r+"
|
|
Packit |
1c1d7e |
try_create = FALSE;
|
|
Packit |
1c1d7e |
} else {
|
|
Packit |
1c1d7e |
break;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
if ( fh ) {
|
|
Packit |
1c1d7e |
FSTAT( FILENO(fh), &st ); // get the stat for later usage
|
|
Packit |
1c1d7e |
} else {
|
|
Packit |
1c1d7e |
ok = FALSE;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
if ( ok ) {
|
|
Packit |
1c1d7e |
setState( IO_Open );
|
|
Packit |
1c1d7e |
// on successful open the file stat was got; now test what type
|
|
Packit |
1c1d7e |
// of file we have
|
|
Packit |
1c1d7e |
if ( (st.st_mode & STAT_MASK) != STAT_REG ) {
|
|
Packit |
1c1d7e |
// non-seekable
|
|
Packit |
1c1d7e |
setType( IO_Sequential );
|
|
Packit |
1c1d7e |
length = INT_MAX;
|
|
Packit |
1c1d7e |
ioIndex = (flags() & IO_Append) == 0 ? 0 : length;
|
|
Packit |
1c1d7e |
} else {
|
|
Packit |
1c1d7e |
length = (int)st.st_size;
|
|
Packit |
1c1d7e |
ioIndex = (flags() & IO_Append) == 0 ? 0 : length;
|
|
Packit |
1c1d7e |
if ( !(flags()&IO_Truncate) && length == 0 && isReadable() ) {
|
|
Packit |
1c1d7e |
// try if you can read from it (if you can, it's a sequential
|
|
Packit |
1c1d7e |
// device; e.g. a file in the /proc filesystem)
|
|
Packit |
1c1d7e |
int c = getch();
|
|
Packit |
1c1d7e |
if ( c != -1 ) {
|
|
Packit |
1c1d7e |
ungetch(c);
|
|
Packit |
1c1d7e |
setType( IO_Sequential );
|
|
Packit |
1c1d7e |
length = INT_MAX;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
} else {
|
|
Packit |
1c1d7e |
init();
|
|
Packit |
1c1d7e |
if ( errno == EMFILE ) // no more file handles/descrs
|
|
Packit |
1c1d7e |
setStatus( IO_ResourceError );
|
|
Packit |
1c1d7e |
else
|
|
Packit |
1c1d7e |
setStatus( IO_OpenError );
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
return ok;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
/*!
|
|
Packit |
1c1d7e |
Opens a file in the mode \e m using an existing file handle \e f.
|
|
Packit |
1c1d7e |
Returns TRUE if successful, otherwise FALSE.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
Example:
|
|
Packit |
1c1d7e |
\code
|
|
Packit |
1c1d7e |
#include <stdio.h>
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
void printError( const char* msg )
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
QFile f;
|
|
Packit |
1c1d7e |
f.open( IO_WriteOnly, stderr );
|
|
Packit |
1c1d7e |
f.writeBlock( msg, qstrlen(msg) ); // write to stderr
|
|
Packit |
1c1d7e |
f.close();
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
\endcode
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
When a QFile is opened using this function, close() does not actually
|
|
Packit |
1c1d7e |
close the file, only flushes it.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
\warning If \e f is \c stdin, \c stdout, \c stderr, you may not
|
|
Packit |
1c1d7e |
be able to seek. See QIODevice::isSequentialAccess() for more
|
|
Packit |
1c1d7e |
information.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
\sa close()
|
|
Packit |
1c1d7e |
*/
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
bool QFile::open( int m, FILE *f )
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
if ( isOpen() ) {
|
|
Packit |
1c1d7e |
#if defined(CHECK_RANGE)
|
|
Packit |
1c1d7e |
qWarning( "QFile::open: File already open" );
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
return FALSE;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
init();
|
|
Packit |
1c1d7e |
setMode( m &~IO_Raw );
|
|
Packit |
1c1d7e |
setState( IO_Open );
|
|
Packit |
1c1d7e |
fh = f;
|
|
Packit |
1c1d7e |
ext_f = TRUE;
|
|
Packit |
1c1d7e |
STATBUF st;
|
|
Packit |
1c1d7e |
FSTAT( FILENO(fh), &st );
|
|
Packit |
1c1d7e |
ioIndex = (int)ftell( fh );
|
|
Packit |
1c1d7e |
if ( (st.st_mode & STAT_MASK) != STAT_REG || f == stdin ) { //stdin is non seekable
|
|
Packit |
1c1d7e |
// non-seekable
|
|
Packit |
1c1d7e |
setType( IO_Sequential );
|
|
Packit |
1c1d7e |
length = INT_MAX;
|
|
Packit |
1c1d7e |
} else {
|
|
Packit |
1c1d7e |
length = (int)st.st_size;
|
|
Packit |
1c1d7e |
if ( !(flags()&IO_Truncate) && length == 0 && isReadable() ) {
|
|
Packit |
1c1d7e |
// try if you can read from it (if you can, it's a sequential
|
|
Packit |
1c1d7e |
// device; e.g. a file in the /proc filesystem)
|
|
Packit |
1c1d7e |
int c = getch();
|
|
Packit |
1c1d7e |
if ( c != -1 ) {
|
|
Packit |
1c1d7e |
ungetch(c);
|
|
Packit |
1c1d7e |
setType( IO_Sequential );
|
|
Packit |
1c1d7e |
length = INT_MAX;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
return TRUE;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
/*!
|
|
Packit |
1c1d7e |
Opens a file in the mode \e m using an existing file descriptor \e f.
|
|
Packit |
1c1d7e |
Returns TRUE if successful, otherwise FALSE.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
When a QFile is opened using this function, close() does not actually
|
|
Packit |
1c1d7e |
close the file.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
\warning If \e f is one of 0 (stdin), 1 (stdout) or 2 (stderr), you may not
|
|
Packit |
1c1d7e |
be able to seek. size() is set to \c INT_MAX (in limits.h).
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
\sa close()
|
|
Packit |
1c1d7e |
*/
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
bool QFile::open( int m, int f )
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
if ( isOpen() ) {
|
|
Packit |
1c1d7e |
#if defined(CHECK_RANGE)
|
|
Packit |
1c1d7e |
qWarning( "QFile::open: File already open" );
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
return FALSE;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
init();
|
|
Packit |
1c1d7e |
setMode( m |IO_Raw );
|
|
Packit |
1c1d7e |
setState( IO_Open );
|
|
Packit |
1c1d7e |
fd = f;
|
|
Packit |
1c1d7e |
ext_f = TRUE;
|
|
Packit |
1c1d7e |
STATBUF st;
|
|
Packit |
1c1d7e |
FSTAT( fd, &st );
|
|
Packit |
1c1d7e |
ioIndex = (int)LSEEK(fd, 0, SEEK_CUR);
|
|
Packit |
1c1d7e |
if ( (st.st_mode & STAT_MASK) != STAT_REG || f == 0 ) { // stdin is not seekable...
|
|
Packit |
1c1d7e |
// non-seekable
|
|
Packit |
1c1d7e |
setType( IO_Sequential );
|
|
Packit |
1c1d7e |
length = INT_MAX;
|
|
Packit |
1c1d7e |
} else {
|
|
Packit |
1c1d7e |
length = (int)st.st_size;
|
|
Packit |
1c1d7e |
if ( length == 0 && isReadable() ) {
|
|
Packit |
1c1d7e |
// try if you can read from it (if you can, it's a sequential
|
|
Packit |
1c1d7e |
// device; e.g. a file in the /proc filesystem)
|
|
Packit |
1c1d7e |
int c = getch();
|
|
Packit |
1c1d7e |
if ( c != -1 ) {
|
|
Packit |
1c1d7e |
ungetch(c);
|
|
Packit |
1c1d7e |
setType( IO_Sequential );
|
|
Packit |
1c1d7e |
length = INT_MAX;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
resetStatus();
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
return TRUE;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
/*!
|
|
Packit |
1c1d7e |
Returns the file size.
|
|
Packit |
1c1d7e |
\sa at()
|
|
Packit |
1c1d7e |
*/
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
uint QFile::size() const
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
STATBUF st;
|
|
Packit |
1c1d7e |
if ( isOpen() ) {
|
|
Packit |
1c1d7e |
FSTAT( fh ? FILENO(fh) : fd, &st );
|
|
Packit |
1c1d7e |
} else {
|
|
Packit |
1c1d7e |
STAT( QFile::encodeName(fn), &st );
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
return (uint)st.st_size;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
/*!
|
|
Packit |
1c1d7e |
\fn int QFile::at() const
|
|
Packit |
1c1d7e |
Returns the file index.
|
|
Packit |
1c1d7e |
\sa size()
|
|
Packit |
1c1d7e |
*/
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
/*!
|
|
Packit |
1c1d7e |
Sets the file index to \e pos. Returns TRUE if successful, otherwise FALSE.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
Example:
|
|
Packit |
1c1d7e |
\code
|
|
Packit |
1c1d7e |
QFile f( "data.bin" );
|
|
Packit |
1c1d7e |
f.open( IO_ReadOnly ); // index set to 0
|
|
Packit |
1c1d7e |
f.at( 100 ); // set index to 100
|
|
Packit |
1c1d7e |
f.at( f.at()+50 ); // set index to 150
|
|
Packit |
1c1d7e |
f.at( f.size()-80 ); // set index to 80 before EOF
|
|
Packit |
1c1d7e |
f.close();
|
|
Packit |
1c1d7e |
\endcode
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
\warning The result is undefined if the file was \link open() opened\endlink
|
|
Packit |
1c1d7e |
using the \c IO_Append specifier.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
\sa size(), open()
|
|
Packit |
1c1d7e |
*/
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
bool QFile::at( int pos )
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
if ( !isOpen() ) {
|
|
Packit |
1c1d7e |
#if defined(CHECK_STATE)
|
|
Packit |
1c1d7e |
qWarning( "QFile::at: File is not open" );
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
return FALSE;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
bool ok;
|
|
Packit |
1c1d7e |
if ( isRaw() ) { // raw file
|
|
Packit |
1c1d7e |
pos = (int)LSEEK(fd, pos, SEEK_SET);
|
|
Packit |
1c1d7e |
ok = pos != -1;
|
|
Packit |
1c1d7e |
} else { // buffered file
|
|
Packit |
1c1d7e |
ok = fseek(fh, pos, SEEK_SET) == 0;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
if ( ok )
|
|
Packit |
1c1d7e |
ioIndex = pos;
|
|
Packit |
1c1d7e |
#if defined(CHECK_RANGE)
|
|
Packit |
1c1d7e |
else
|
|
Packit |
1c1d7e |
qWarning( "QFile::at: Cannot set file position %d", pos );
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
return ok;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
/*!
|
|
Packit |
1c1d7e |
Reads at most \e len bytes from the file into \e p and returns the
|
|
Packit |
1c1d7e |
number of bytes actually read.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
Returns -1 if a serious error occurred.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
\warning We have experienced problems with some C libraries when a buffered
|
|
Packit |
1c1d7e |
file is opened for both reading and writing. If a read operation takes place
|
|
Packit |
1c1d7e |
immediately after a write operation, the read buffer contains garbage data.
|
|
Packit |
1c1d7e |
Worse, the same garbage is written to the file. Calling flush() before
|
|
Packit |
1c1d7e |
readBlock() solved this problem.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
\sa writeBlock()
|
|
Packit |
1c1d7e |
*/
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
int QFile::readBlock( char *p, uint len )
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
#if defined(CHECK_NULL)
|
|
Packit |
1c1d7e |
if ( !p )
|
|
Packit |
1c1d7e |
qWarning( "QFile::readBlock: Null pointer error" );
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
#if defined(CHECK_STATE)
|
|
Packit |
1c1d7e |
if ( !isOpen() ) { // file not open
|
|
Packit |
1c1d7e |
qWarning( "QFile::readBlock: File not open" );
|
|
Packit |
1c1d7e |
return -1;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
if ( !isReadable() ) { // reading not permitted
|
|
Packit |
1c1d7e |
qWarning( "QFile::readBlock: Read operation not permitted" );
|
|
Packit |
1c1d7e |
return -1;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
int nread = 0; // number of bytes read
|
|
Packit |
1c1d7e |
if ( !ungetchBuffer.isEmpty() ) {
|
|
Packit |
1c1d7e |
// need to add these to the returned string.
|
|
Packit |
1c1d7e |
int l = ungetchBuffer.length();
|
|
Packit |
1c1d7e |
while( nread < l ) {
|
|
Packit |
1c1d7e |
*p = ungetchBuffer[ l - nread - 1 ];
|
|
Packit |
1c1d7e |
p++;
|
|
Packit |
1c1d7e |
nread++;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
ungetchBuffer.truncate( l - nread );
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
if ( nread < (int)len ) {
|
|
Packit |
1c1d7e |
if ( isRaw() ) { // raw file
|
|
Packit |
1c1d7e |
nread += (int)READ( fd, p, len-nread );
|
|
Packit |
1c1d7e |
if ( len && nread <= 0 ) {
|
|
Packit |
1c1d7e |
nread = 0;
|
|
Packit |
1c1d7e |
setStatus(IO_ReadError);
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
} else { // buffered file
|
|
Packit |
1c1d7e |
nread += (int)fread( p, 1, len-nread, fh );
|
|
Packit |
1c1d7e |
if ( (uint)nread != len ) {
|
|
Packit |
1c1d7e |
if ( ferror( fh ) || nread==0 )
|
|
Packit |
1c1d7e |
setStatus(IO_ReadError);
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
ioIndex += nread;
|
|
Packit |
1c1d7e |
return nread;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
/*! \overload int writeBlock( const QByteArray& data )
|
|
Packit |
1c1d7e |
*/
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
/*! \reimp
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
Writes \e len bytes from \e p to the file and returns the number of
|
|
Packit |
1c1d7e |
bytes actually written.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
Returns -1 if a serious error occurred.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
\warning When working with buffered files, data may not be written
|
|
Packit |
1c1d7e |
to the file at once. Call flush() to make sure the data is really
|
|
Packit |
1c1d7e |
written.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
\sa readBlock()
|
|
Packit |
1c1d7e |
*/
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
int QFile::writeBlock( const char *p, uint len )
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
#if defined(CHECK_NULL)
|
|
Packit |
1c1d7e |
if ( p == 0 && len != 0 )
|
|
Packit |
1c1d7e |
qWarning( "QFile::writeBlock: Null pointer error" );
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
#if defined(CHECK_STATE)
|
|
Packit |
1c1d7e |
if ( !isOpen() ) { // file not open
|
|
Packit |
1c1d7e |
qWarning( "QFile::writeBlock: File not open" );
|
|
Packit |
1c1d7e |
return -1;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
if ( !isWritable() ) { // writing not permitted
|
|
Packit |
1c1d7e |
qWarning( "QFile::writeBlock: Write operation not permitted" );
|
|
Packit |
1c1d7e |
return -1;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
#endif
|
|
Packit |
1c1d7e |
if (p==0) return 0;
|
|
Packit |
1c1d7e |
int nwritten; // number of bytes written
|
|
Packit |
1c1d7e |
if ( isRaw() ) // raw file
|
|
Packit |
1c1d7e |
nwritten = (int)WRITE( fd, p, len );
|
|
Packit |
1c1d7e |
else // buffered file
|
|
Packit |
1c1d7e |
nwritten = (int)fwrite( p, 1, len, fh );
|
|
Packit |
1c1d7e |
if ( nwritten != (int)len ) { // write error
|
|
Packit |
1c1d7e |
if ( errno == ENOSPC ) // disk is full
|
|
Packit |
1c1d7e |
setStatus( IO_ResourceError );
|
|
Packit |
1c1d7e |
else
|
|
Packit |
1c1d7e |
setStatus( IO_WriteError );
|
|
Packit |
1c1d7e |
if ( isRaw() ) // recalc file position
|
|
Packit |
1c1d7e |
ioIndex = (int)LSEEK( fd, 0, SEEK_CUR );
|
|
Packit |
1c1d7e |
else
|
|
Packit |
1c1d7e |
ioIndex = fseek( fh, 0, SEEK_CUR );
|
|
Packit |
1c1d7e |
} else {
|
|
Packit |
1c1d7e |
ioIndex += nwritten;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
if ( ioIndex > length ) // update file length
|
|
Packit |
1c1d7e |
length = ioIndex;
|
|
Packit |
1c1d7e |
return nwritten;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
/*!
|
|
Packit |
1c1d7e |
Returns the file handle of the file.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
This is a small positive integer, suitable for use with C library
|
|
Packit |
1c1d7e |
functions such as fdopen() and fcntl(), as well as with QSocketNotifier.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
If the file is not open or there is an error, handle() returns -1.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
\sa QSocketNotifier
|
|
Packit |
1c1d7e |
*/
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
int QFile::handle() const
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
if ( !isOpen() )
|
|
Packit |
1c1d7e |
return -1;
|
|
Packit |
1c1d7e |
else if ( fh )
|
|
Packit |
1c1d7e |
return FILENO( fh );
|
|
Packit |
1c1d7e |
else
|
|
Packit |
1c1d7e |
return fd;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
/*!
|
|
Packit |
1c1d7e |
Closes an open file.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
The file is not closed if it was opened with an existing file handle.
|
|
Packit |
1c1d7e |
If the existing file handle is a \c FILE*, the file is flushed.
|
|
Packit |
1c1d7e |
If the existing file handle is an \c int file descriptor, nothing
|
|
Packit |
1c1d7e |
is done to the file.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
Some "write-behind" filesystems may report an unspecified error on
|
|
Packit |
1c1d7e |
closing the file. These errors only indicate that something may
|
|
Packit |
1c1d7e |
have gone wrong since the previous open(). In such a case status()
|
|
Packit |
1c1d7e |
reports IO_UnspecifiedError after close(), otherwise IO_Ok.
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
\sa open(), flush()
|
|
Packit |
1c1d7e |
*/
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
void QFile::close()
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
bool ok = FALSE;
|
|
Packit |
1c1d7e |
if ( isOpen() ) { // file is not open
|
|
Packit |
1c1d7e |
if ( fh ) { // buffered file
|
|
Packit |
1c1d7e |
if ( ext_f )
|
|
Packit |
1c1d7e |
ok = fflush( fh ) != -1; // flush instead of closing
|
|
Packit |
1c1d7e |
else
|
|
Packit |
1c1d7e |
ok = fclose( fh ) != -1;
|
|
Packit |
1c1d7e |
} else { // raw file
|
|
Packit |
1c1d7e |
if ( ext_f )
|
|
Packit |
1c1d7e |
ok = TRUE; // cannot close
|
|
Packit |
1c1d7e |
else
|
|
Packit |
1c1d7e |
ok = CLOSE( fd ) != -1;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
init(); // restore internal state
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
if (!ok)
|
|
Packit |
1c1d7e |
setStatus (IO_UnspecifiedError);
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
return;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
int64 QFile::pos() const
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
if (isOpen())
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
// TODO: support 64 bit size
|
|
Packit |
1c1d7e |
return ftell( fh );
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
return -1;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
int64 QFile::toEnd()
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
if (isOpen())
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
// TODO: support 64 bit size
|
|
Packit |
1c1d7e |
if (fseek( fh, 0, SEEK_END )!=-1)
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
return ftell( fh );
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
return -1;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
|
|
Packit |
1c1d7e |
bool QFile::seek( int64 pos )
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
if (isOpen())
|
|
Packit |
1c1d7e |
{
|
|
Packit |
1c1d7e |
// TODO: support 64 bit size
|
|
Packit |
1c1d7e |
return fseek( fh, (long)pos, SEEK_SET )!=-1;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
return FALSE;
|
|
Packit |
1c1d7e |
}
|
|
Packit |
1c1d7e |
|