|
|
|
/****************************************************************************
|
|
|
|
**
|
|
|
|
** Implementation of TQFile class
|
|
|
|
**
|
|
|
|
** Created : 950628
|
|
|
|
**
|
|
|
|
** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
|
|
|
|
**
|
|
|
|
** This file is part of the tools module of the TQt GUI Toolkit.
|
|
|
|
**
|
|
|
|
** This file may be used under the terms of the GNU General
|
|
|
|
** Public License versions 2.0 or 3.0 as published by the Free
|
|
|
|
** Software Foundation and appearing in the files LICENSE.GPL2
|
|
|
|
** and LICENSE.GPL3 included in the packaging of this file.
|
|
|
|
** Alternatively you may (at your option) use any later version
|
|
|
|
** of the GNU General Public License if such license has been
|
|
|
|
** publicly approved by Trolltech ASA (or its successors, if any)
|
|
|
|
** and the KDE Free TQt Foundation.
|
|
|
|
**
|
|
|
|
** Please review the following information to ensure GNU General
|
|
|
|
** Public Licensing requirements will be met:
|
|
|
|
** http://trolltech.com/products/qt/licenses/licensing/opensource/.
|
|
|
|
** If you are unsure which license is appropriate for your use, please
|
|
|
|
** review the following information:
|
|
|
|
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
|
|
|
|
** or contact the sales department at sales@trolltech.com.
|
|
|
|
**
|
|
|
|
** This file may be used under the terms of the Q Public License as
|
|
|
|
** defined by Trolltech ASA and appearing in the file LICENSE.TQPL
|
|
|
|
** included in the packaging of this file. Licensees holding valid TQt
|
|
|
|
** Commercial licenses may use this file in accordance with the TQt
|
|
|
|
** Commercial License Agreement provided with the Software.
|
|
|
|
**
|
|
|
|
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
|
|
|
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
|
|
|
** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
|
|
|
|
** herein.
|
|
|
|
**
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
#include "qplatformdefs.h"
|
|
|
|
|
|
|
|
// POSIX Large File Support redefines open -> open64
|
|
|
|
static inline int qt_open(const char *pathname, int flags, mode_t mode)
|
|
|
|
{ return ::open(pathname, flags, mode); }
|
|
|
|
#if defined(open)
|
|
|
|
# undef open
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// POSIX Large File Support redefines truncate -> truncate64
|
|
|
|
#if defined(truncate)
|
|
|
|
# undef truncate
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "ntqfile.h"
|
|
|
|
#include <errno.h>
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
extern const char* qt_fileerr_read;
|
|
|
|
|
|
|
|
bool qt_file_access( const TQString& fn, int t )
|
|
|
|
{
|
|
|
|
if ( fn.isEmpty() )
|
|
|
|
return FALSE;
|
|
|
|
return ::access( TQFile::encodeName(fn), t ) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\overload
|
|
|
|
Removes the file \a fileName.
|
|
|
|
Returns TRUE if successful, otherwise FALSE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool TQFile::remove( const TQString &fileName )
|
|
|
|
{
|
|
|
|
if ( fileName.isEmpty() ) {
|
|
|
|
#if defined(QT_CHECK_NULL)
|
|
|
|
tqWarning( "TQFile::remove: Empty or null file name" );
|
|
|
|
#endif
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return unlink( TQFile::encodeName(fileName) ) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(O_NONBLOCK)
|
|
|
|
# define HAS_ASYNC_FILEMODE
|
|
|
|
# define OPEN_ASYNC O_NONBLOCK
|
|
|
|
#elif defined(O_NDELAY)
|
|
|
|
# define HAS_ASYNC_FILEMODE
|
|
|
|
# define OPEN_ASYNC O_NDELAY
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Opens the file specified by the file name currently set, using the
|
|
|
|
mode \a m. Returns TRUE if successful, otherwise FALSE.
|
|
|
|
|
|
|
|
\keyword IO_Raw
|
|
|
|
\keyword IO_ReadOnly
|
|
|
|
\keyword IO_WriteOnly
|
|
|
|
\keyword IO_ReadWrite
|
|
|
|
\keyword IO_Append
|
|
|
|
\keyword IO_Truncate
|
|
|
|
\keyword IO_Translate
|
|
|
|
|
|
|
|
The mode parameter \a m must be a combination of the following flags:
|
|
|
|
\table
|
|
|
|
\header \i Flag \i Meaning
|
|
|
|
\row \i IO_Raw
|
|
|
|
\i Raw (non-buffered) file access.
|
|
|
|
\row \i IO_ReadOnly
|
|
|
|
\i Opens the file in read-only mode.
|
|
|
|
\row \i IO_WriteOnly
|
|
|
|
\i Opens the file in write-only mode. If this flag is used
|
|
|
|
with another flag, e.g. \c IO_ReadOnly or \c IO_Raw or \c
|
|
|
|
IO_Append, the file is \e not truncated; but if used on
|
|
|
|
its own (or with \c IO_Truncate), the file is truncated.
|
|
|
|
\row \i IO_ReadWrite
|
|
|
|
\i Opens the file in read/write mode, equivalent to \c
|
|
|
|
(IO_ReadOnly | IO_WriteOnly).
|
|
|
|
\row \i IO_Append
|
|
|
|
\i Opens the file in append mode. (You must actually use \c
|
|
|
|
(IO_WriteOnly | IO_Append) to make the file writable and
|
|
|
|
to go into append mode.) This mode is very useful when you
|
|
|
|
want to write something to a log file. The file index is
|
|
|
|
set to the end of the file. Note that the result is
|
|
|
|
undefined if you position the file index manually using
|
|
|
|
at() in append mode.
|
|
|
|
\row \i IO_Truncate
|
|
|
|
\i Truncates the file.
|
|
|
|
\row \i IO_Translate
|
|
|
|
\i Enables carriage returns and linefeed translation for text
|
|
|
|
files under Windows.
|
|
|
|
\endtable
|
|
|
|
|
|
|
|
The raw access mode is best when I/O is block-operated using a 4KB
|
|
|
|
block size or greater. Buffered access works better when reading
|
|
|
|
small portions of data at a time.
|
|
|
|
|
|
|
|
\warning When working with buffered files, data may not be written
|
|
|
|
to the file at once. Call flush() to make sure that the data is
|
|
|
|
really written.
|
|
|
|
|
|
|
|
\warning If you have a buffered file opened for both reading and
|
|
|
|
writing you must not perform an input operation immediately after
|
|
|
|
an output operation or vice versa. You should always call flush()
|
|
|
|
or a file positioning operation, e.g. at(), between input and
|
|
|
|
output operations, otherwise the buffer may contain garbage.
|
|
|
|
|
|
|
|
If the file does not exist and \c IO_WriteOnly or \c IO_ReadWrite
|
|
|
|
is specified, it is created.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
\code
|
|
|
|
TQFile f1( "/tmp/data.bin" );
|
|
|
|
f1.open( IO_Raw | IO_ReadWrite );
|
|
|
|
|
|
|
|
TQFile f2( "readme.txt" );
|
|
|
|
f2.open( IO_ReadOnly | IO_Translate );
|
|
|
|
|
|
|
|
TQFile f3( "audit.log" );
|
|
|
|
f3.open( IO_WriteOnly | IO_Append );
|
|
|
|
\endcode
|
|
|
|
|
|
|
|
\sa name(), close(), isOpen(), flush()
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool TQFile::open( int m )
|
|
|
|
{
|
|
|
|
if ( isOpen() ) { // file already open
|
|
|
|
#if defined(QT_CHECK_STATE)
|
|
|
|
tqWarning( "TQFile::open: File already open" );
|
|
|
|
#endif
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if ( fn.isEmpty() ) { // no file name defined
|
|
|
|
#if defined(QT_CHECK_NULL)
|
|
|
|
tqWarning( "TQFile::open: No file name specified" );
|
|
|
|
#endif
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
init(); // reset params
|
|
|
|
setMode( m );
|
|
|
|
if ( !(isReadable() || isWritable()) ) {
|
|
|
|
#if defined(QT_CHECK_RANGE)
|
|
|
|
tqWarning( "TQFile::open: File access not specified" );
|
|
|
|
#endif
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
bool ok = TRUE;
|
|
|
|
struct stat st;
|
|
|
|
if ( isRaw() ) {
|
|
|
|
int oflags = O_RDONLY;
|
|
|
|
if ( isReadable() && isWritable() )
|
|
|
|
oflags = O_RDWR;
|
|
|
|
else if ( isWritable() )
|
|
|
|
oflags = O_WRONLY;
|
|
|
|
if ( flags() & IO_Append ) { // append to end of file?
|
|
|
|
if ( flags() & IO_Truncate )
|
|
|
|
oflags |= (O_CREAT | O_TRUNC);
|
|
|
|
else
|
|
|
|
oflags |= (O_APPEND | O_CREAT);
|
|
|
|
setFlags( flags() | IO_WriteOnly ); // append implies write
|
|
|
|
} else if ( isWritable() ) { // create/trunc if writable
|
|
|
|
if ( flags() & IO_Truncate )
|
|
|
|
oflags |= (O_CREAT | O_TRUNC);
|
|
|
|
else
|
|
|
|
oflags |= O_CREAT;
|
|
|
|
}
|
|
|
|
#if defined(HAS_TEXT_FILEMODE)
|
|
|
|
if ( isTranslated() )
|
|
|
|
oflags |= OPEN_TEXT;
|
|
|
|
else
|
|
|
|
oflags |= OPEN_BINARY;
|
|
|
|
#endif
|
|
|
|
#if defined(HAS_ASYNC_FILEMODE)
|
|
|
|
if ( isAsynchronous() )
|
|
|
|
oflags |= OPEN_ASYNC;
|
|
|
|
#endif
|
|
|
|
fd = qt_open( TQFile::encodeName(fn), oflags, 0666 );
|
|
|
|
|
|
|
|
if ( fd != -1 ) { // open successful
|
|
|
|
::fstat( fd, &st ); // get the stat for later usage
|
|
|
|
} else {
|
|
|
|
ok = FALSE;
|
|
|
|
}
|
|
|
|
} else { // buffered file I/O
|
|
|
|
TQCString perm;
|
|
|
|
char perm2[4];
|
|
|
|
bool try_create = FALSE;
|
|
|
|
if ( flags() & IO_Append ) { // append to end of file?
|
|
|
|
setFlags( flags() | IO_WriteOnly ); // append implies write
|
|
|
|
perm = isReadable() ? "a+" : "a";
|
|
|
|
} else {
|
|
|
|
if ( isReadWrite() ) {
|
|
|
|
if ( flags() & IO_Truncate ) {
|
|
|
|
perm = "w+";
|
|
|
|
} else {
|
|
|
|
perm = "r+";
|
|
|
|
try_create = TRUE; // try to create if not exists
|
|
|
|
}
|
|
|
|
} else if ( isReadable() ) {
|
|
|
|
perm = "r";
|
|
|
|
} else if ( isWritable() ) {
|
|
|
|
perm = "w";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qstrcpy( perm2, perm );
|
|
|
|
#if defined(HAS_TEXT_FILEMODE)
|
|
|
|
if ( isTranslated() )
|
|
|
|
strcat( perm2, "t" );
|
|
|
|
else
|
|
|
|
strcat( perm2, "b" );
|
|
|
|
#endif
|
|
|
|
for (;;) { // At most twice
|
|
|
|
|
|
|
|
fh = fopen( TQFile::encodeName(fn), perm2 );
|
|
|
|
|
|
|
|
if ( !fh && try_create ) {
|
|
|
|
perm2[0] = 'w'; // try "w+" instead of "r+"
|
|
|
|
try_create = FALSE;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( fh ) {
|
|
|
|
::fstat( fileno(fh), &st ); // get the stat for later usage
|
|
|
|
} else {
|
|
|
|
ok = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( ok ) {
|
|
|
|
setState( IO_Open );
|
|
|
|
// on successful open the file stat was got; now test what type
|
|
|
|
// of file we have
|
|
|
|
if ( (st.st_mode & S_IFMT) != S_IFREG ) {
|
|
|
|
// non-seekable
|
|
|
|
setType( IO_Sequential );
|
|
|
|
length = INT_MAX;
|
|
|
|
ioIndex = 0;
|
|
|
|
} else {
|
|
|
|
#if defined(QT_LARGEFILE_SUPPORT) && !defined(QT_ABI_QT4)
|
|
|
|
length = st.st_size > UINT_MAX ? UINT_MAX : (Offset)st.st_size;
|
|
|
|
#else
|
|
|
|
length = (Offset)st.st_size;
|
|
|
|
#endif
|
|
|
|
ioIndex = (flags() & IO_Append) == 0 ? 0 : length;
|
|
|
|
if ( !(flags()&IO_Truncate) && length == 0 && isReadable() ) {
|
|
|
|
// try if you can read from it (if you can, it's a sequential
|
|
|
|
// device; e.g. a file in the /proc filesystem)
|
|
|
|
int c = getch();
|
|
|
|
if ( c != -1 ) {
|
|
|
|
ungetch(c);
|
|
|
|
setType( IO_Sequential );
|
|
|
|
length = INT_MAX;
|
|
|
|
ioIndex = 0;
|
|
|
|
}
|
|
|
|
resetStatus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
init();
|
|
|
|
if ( errno == EMFILE ) // no more file handles/descrs
|
|
|
|
setStatus( IO_ResourceError );
|
|
|
|
else
|
|
|
|
setStatus( IO_OpenError );
|
|
|
|
setErrorStringErrno( errno );
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\overload
|
|
|
|
Opens a file in the mode \a m using an existing file handle \a f.
|
|
|
|
Returns TRUE if successful, otherwise FALSE.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
\code
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
void printError( const char* msg )
|
|
|
|
{
|
|
|
|
TQFile f;
|
|
|
|
f.open( IO_WriteOnly, stderr );
|
|
|
|
f.writeBlock( msg, tqstrlen(msg) ); // write to stderr
|
|
|
|
f.close();
|
|
|
|
}
|
|
|
|
\endcode
|
|
|
|
|
|
|
|
When a TQFile is opened using this function, close() does not actually
|
|
|
|
close the file, only flushes it.
|
|
|
|
|
|
|
|
\warning If \a f is \c stdin, \c stdout, \c stderr, you may not
|
|
|
|
be able to seek. See TQIODevice::isSequentialAccess() for more
|
|
|
|
information.
|
|
|
|
|
|
|
|
\sa close()
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool TQFile::open( int m, FILE *f )
|
|
|
|
{
|
|
|
|
if ( isOpen() ) {
|
|
|
|
#if defined(QT_CHECK_RANGE)
|
|
|
|
tqWarning( "TQFile::open: File already open" );
|
|
|
|
#endif
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
init();
|
|
|
|
setMode( m &~IO_Raw );
|
|
|
|
setState( IO_Open );
|
|
|
|
fh = f;
|
|
|
|
ext_f = TRUE;
|
|
|
|
struct stat st;
|
|
|
|
::fstat( fileno(fh), &st );
|
|
|
|
#if defined(QT_LARGEFILE_SUPPORT)
|
|
|
|
#if !defined(QT_ABI_QT4)
|
|
|
|
off_t tmp = ftello( fh );
|
|
|
|
ioIndex = tmp > UINT_MAX ? UINT_MAX : (Offset)tmp;
|
|
|
|
#else
|
|
|
|
ioIndex = (Offset)ftello( fh );
|
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
ioIndex = (Offset)ftell( fh );
|
|
|
|
#endif
|
|
|
|
if ( (st.st_mode & S_IFMT) != S_IFREG || f == stdin ) { //stdin is non seekable
|
|
|
|
// non-seekable
|
|
|
|
setType( IO_Sequential );
|
|
|
|
length = INT_MAX;
|
|
|
|
ioIndex = 0;
|
|
|
|
} else {
|
|
|
|
#if defined(QT_LARGEFILE_SUPPORT) && !defined(QT_ABI_QT4)
|
|
|
|
length = st.st_size > UINT_MAX ? UINT_MAX : (Offset)st.st_size;
|
|
|
|
#else
|
|
|
|
length = (Offset)st.st_size;
|
|
|
|
#endif
|
|
|
|
if ( !(flags()&IO_Truncate) && length == 0 && isReadable() ) {
|
|
|
|
// try if you can read from it (if you can, it's a sequential
|
|
|
|
// device; e.g. a file in the /proc filesystem)
|
|
|
|
int c = getch();
|
|
|
|
if ( c != -1 ) {
|
|
|
|
ungetch(c);
|
|
|
|
setType( IO_Sequential );
|
|
|
|
length = INT_MAX;
|
|
|
|
ioIndex = 0;
|
|
|
|
}
|
|
|
|
resetStatus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\overload
|
|
|
|
Opens a file in the mode \a m using an existing file descriptor \a f.
|
|
|
|
Returns TRUE if successful, otherwise FALSE.
|
|
|
|
|
|
|
|
When a TQFile is opened using this function, close() does not actually
|
|
|
|
close the file.
|
|
|
|
|
|
|
|
The TQFile that is opened using this function, is automatically set to be in
|
|
|
|
raw mode; this means that the file input/output functions are slow. If you
|
|
|
|
run into performance issues, you should try to use one of the other open
|
|
|
|
functions.
|
|
|
|
|
|
|
|
\warning If \a f is one of 0 (stdin), 1 (stdout) or 2 (stderr), you may not
|
|
|
|
be able to seek. size() is set to \c INT_MAX (in limits.h).
|
|
|
|
|
|
|
|
\sa close()
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
bool TQFile::open( int m, int f )
|
|
|
|
{
|
|
|
|
if ( isOpen() ) {
|
|
|
|
#if defined(QT_CHECK_RANGE)
|
|
|
|
tqWarning( "TQFile::open: File already open" );
|
|
|
|
#endif
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
init();
|
|
|
|
setMode( m |IO_Raw );
|
|
|
|
setState( IO_Open );
|
|
|
|
fd = f;
|
|
|
|
ext_f = TRUE;
|
|
|
|
struct stat st;
|
|
|
|
::fstat( fd, &st );
|
|
|
|
#if defined(QT_LARGEFILE_SUPPORT) && !defined(QT_ABI_QT4)
|
|
|
|
off_t tmp = ::lseek(fd, 0, SEEK_CUR);
|
|
|
|
ioIndex = tmp > UINT_MAX ? UINT_MAX : (Offset)tmp;
|
|
|
|
#else
|
|
|
|
ioIndex = (Offset)::lseek(fd, 0, SEEK_CUR);
|
|
|
|
#endif
|
|
|
|
if ( (st.st_mode & S_IFMT) != S_IFREG || f == 0 ) { // stdin is not seekable...
|
|
|
|
// non-seekable
|
|
|
|
setType( IO_Sequential );
|
|
|
|
length = INT_MAX;
|
|
|
|
ioIndex = 0;
|
|
|
|
} else {
|
|
|
|
#if defined(QT_LARGEFILE_SUPPORT) && !defined(QT_ABI_QT4)
|
|
|
|
length = st.st_size > UINT_MAX ? UINT_MAX : (Offset)st.st_size;
|
|
|
|
#else
|
|
|
|
length = (Offset)st.st_size;
|
|
|
|
#endif
|
|
|
|
if ( length == 0 && isReadable() ) {
|
|
|
|
// try if you can read from it (if you can, it's a sequential
|
|
|
|
// device; e.g. a file in the /proc filesystem)
|
|
|
|
int c = getch();
|
|
|
|
if ( c != -1 ) {
|
|
|
|
ungetch(c);
|
|
|
|
setType( IO_Sequential );
|
|
|
|
length = INT_MAX;
|
|
|
|
ioIndex = 0;
|
|
|
|
}
|
|
|
|
resetStatus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns the file size.
|
|
|
|
\sa at()
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQIODevice::Offset TQFile::size() const
|
|
|
|
{
|
|
|
|
struct stat st;
|
|
|
|
int ret = 0;
|
|
|
|
if ( isOpen() ) {
|
|
|
|
ret = ::fstat( fh ? fileno(fh) : fd, &st );
|
|
|
|
} else {
|
|
|
|
ret = ::stat( TQFile::encodeName(fn), &st );
|
|
|
|
}
|
|
|
|
if ( ret == -1 )
|
|
|
|
return 0;
|
|
|
|
#if defined(QT_LARGEFILE_SUPPORT) && !defined(QT_ABI_QT4)
|
|
|
|
return (uint)st.st_size > UINT_MAX ? UINT_MAX : (Offset)st.st_size;
|
|
|
|
#else
|
|
|
|
return st.st_size;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\overload
|
|
|
|
|
|
|
|
Sets the file index to \a pos. Returns TRUE if successful;
|
|
|
|
otherwise returns FALSE.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
\code
|
|
|
|
TQFile f( "data.bin" );
|
|
|
|
f.open( IO_ReadOnly ); // index set to 0
|
|
|
|
f.at( 100 ); // set index to 100
|
|
|
|
f.at( f.at()+50 ); // set index to 150
|
|
|
|
f.at( f.size()-80 ); // set index to 80 before EOF
|
|
|
|
f.close();
|
|
|
|
\endcode
|
|
|
|
|
|
|
|
Use \c at() without arguments to retrieve the file offset.
|
|
|
|
|
|
|
|
\warning The result is undefined if the file was open()'ed using
|
|
|
|
the \c IO_Append specifier.
|
|
|
|
|
|
|
|
\sa size(), open()
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool TQFile::at( Offset pos )
|
|
|
|
{
|
|
|
|
if ( !isOpen() ) {
|
|
|
|
#if defined(QT_CHECK_STATE)
|
|
|
|
tqWarning( "TQFile::at: File is not open" );
|
|
|
|
#endif
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if ( isSequentialAccess() )
|
|
|
|
return FALSE;
|
|
|
|
bool ok;
|
|
|
|
if ( isRaw() ) {
|
|
|
|
off_t l = ::lseek( fd, pos, SEEK_SET );
|
|
|
|
ok = ( l != -1 );
|
|
|
|
pos = (Offset)l;
|
|
|
|
} else { // buffered file
|
|
|
|
#if defined(QT_LARGEFILE_SUPPORT)
|
|
|
|
ok = ( ::fseeko(fh, pos, SEEK_SET) == 0 );
|
|
|
|
#else
|
|
|
|
ok = ( ::fseek(fh, pos, SEEK_SET) == 0 );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
if ( ok )
|
|
|
|
#if defined(QT_LARGEFILE_SUPPORT) && !defined(QT_ABI_QT4)
|
|
|
|
ioIndex = pos > UINT_MAX ? UINT_MAX : (Offset)pos;
|
|
|
|
#else
|
|
|
|
ioIndex = (Offset)pos;
|
|
|
|
#endif
|
|
|
|
#if defined(QT_CHECK_RANGE)
|
|
|
|
else
|
|
|
|
#if defined(QT_ABI_QT4)
|
|
|
|
tqWarning( "TQFile::at: Cannot set file position %lld", pos );
|
|
|
|
#else
|
|
|
|
tqWarning( "TQFile::at: Cannot set file position %lu", pos );
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\reimp
|
|
|
|
|
|
|
|
\warning We have experienced problems with some C libraries when a buffered
|
|
|
|
file is opened for both reading and writing. If a read operation takes place
|
|
|
|
immediately after a write operation, the read buffer contains garbage data.
|
|
|
|
Worse, the same garbage is written to the file. Calling flush() before
|
|
|
|
readBlock() solved this problem.
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQ_LONG TQFile::readBlock( char *p, TQ_ULONG len )
|
|
|
|
{
|
|
|
|
if ( !len ) // nothing to do
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#if defined(QT_CHECK_NULL)
|
|
|
|
if ( !p )
|
|
|
|
tqWarning( "TQFile::readBlock: Null pointer error" );
|
|
|
|
#endif
|
|
|
|
#if defined(QT_CHECK_STATE)
|
|
|
|
if ( !isOpen() ) {
|
|
|
|
tqWarning( "TQFile::readBlock: File not open" );
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if ( !isReadable() ) {
|
|
|
|
tqWarning( "TQFile::readBlock: Read operation not permitted" );
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
TQ_ULONG nread = 0; // number of bytes read
|
|
|
|
if ( !ungetchBuffer.isEmpty() ) {
|
|
|
|
// need to add these to the returned string.
|
|
|
|
uint l = ungetchBuffer.length();
|
|
|
|
while( nread < l ) {
|
|
|
|
*p = ungetchBuffer.at( l - nread - 1 );
|
|
|
|
p++;
|
|
|
|
nread++;
|
|
|
|
}
|
|
|
|
ungetchBuffer.truncate( l - nread );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( nread < len ) {
|
|
|
|
if ( isRaw() ) { // raw file
|
|
|
|
nread += ::read( fd, p, len-nread );
|
|
|
|
if ( len && nread <= 0 ) {
|
|
|
|
nread = 0;
|
|
|
|
setStatus(IO_ReadError);
|
|
|
|
setErrorStringErrno( errno );
|
|
|
|
}
|
|
|
|
} else { // buffered file
|
|
|
|
nread += fread( p, 1, len-nread, fh );
|
|
|
|
if ( (uint)nread != len ) {
|
|
|
|
if ( ferror( fh ) || nread==0 ) {
|
|
|
|
setStatus(IO_ReadError);
|
|
|
|
setErrorString( qt_fileerr_read );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !isSequentialAccess() )
|
|
|
|
ioIndex += nread;
|
|
|
|
return nread;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*! \reimp
|
|
|
|
|
|
|
|
Writes \a len bytes from \a p to the file and returns the number of
|
|
|
|
bytes actually written.
|
|
|
|
|
|
|
|
Returns -1 if a serious error occurred.
|
|
|
|
|
|
|
|
\warning When working with buffered files, data may not be written
|
|
|
|
to the file at once. Call flush() to make sure the data is really
|
|
|
|
written.
|
|
|
|
|
|
|
|
\sa readBlock()
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQ_LONG TQFile::writeBlock( const char *p, TQ_ULONG len )
|
|
|
|
{
|
|
|
|
if ( !len ) // nothing to do
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#if defined(QT_CHECK_NULL)
|
|
|
|
if ( p == 0 && len != 0 )
|
|
|
|
tqWarning( "TQFile::writeBlock: Null pointer error" );
|
|
|
|
#endif
|
|
|
|
#if defined(QT_CHECK_STATE)
|
|
|
|
if ( !isOpen() ) { // file not open
|
|
|
|
tqWarning( "TQFile::writeBlock: File not open" );
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if ( !isWritable() ) { // writing not permitted
|
|
|
|
tqWarning( "TQFile::writeBlock: Write operation not permitted" );
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
TQ_ULONG nwritten; // number of bytes written
|
|
|
|
if ( isRaw() ) // raw file
|
|
|
|
nwritten = ::write( fd, (void *)p, len );
|
|
|
|
else // buffered file
|
|
|
|
nwritten = fwrite( p, 1, len, fh );
|
|
|
|
if ( nwritten != len ) { // write error
|
|
|
|
if ( errno == ENOSPC ) // disk is full
|
|
|
|
setStatus( IO_ResourceError );
|
|
|
|
else
|
|
|
|
setStatus( IO_WriteError );
|
|
|
|
setErrorStringErrno( errno );
|
|
|
|
if ( !isSequentialAccess() ) {
|
|
|
|
if ( isRaw() ) { // recalc file position
|
|
|
|
#if defined(QT_LARGEFILE_SUPPORT) && !defined(QT_ABI_QT4)
|
|
|
|
off_t tmp = ::lseek( fd, 0, SEEK_CUR );
|
|
|
|
ioIndex = tmp > UINT_MAX ? UINT_MAX : (Offset)tmp;
|
|
|
|
#else
|
|
|
|
ioIndex = (Offset)::lseek( fd, 0, SEEK_CUR );
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
#if defined(QT_LARGEFILE_SUPPORT)
|
|
|
|
#if !defined(QT_ABI_QT4)
|
|
|
|
off_t tmp = (Offset)::fseeko( fh, 0, SEEK_CUR );
|
|
|
|
ioIndex = tmp > UINT_MAX ? UINT_MAX : (Offset)tmp;
|
|
|
|
#else
|
|
|
|
ioIndex = (Offset)::fseeko( fh, 0, SEEK_CUR );
|
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
ioIndex = (Offset)::fseek( fh, 0, SEEK_CUR );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( !isSequentialAccess() )
|
|
|
|
ioIndex += nwritten;
|
|
|
|
}
|
|
|
|
if ( ioIndex > length ) // update file length
|
|
|
|
length = ioIndex;
|
|
|
|
return nwritten;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns the file handle of the file.
|
|
|
|
|
|
|
|
This is a small positive integer, suitable for use with C library
|
|
|
|
functions such as fdopen() and fcntl(). On systems that use file
|
|
|
|
descriptors for sockets (ie. Unix systems, but not Windows) the handle
|
|
|
|
can be used with TQSocketNotifier as well.
|
|
|
|
|
|
|
|
If the file is not open or there is an error, handle() returns -1.
|
|
|
|
|
|
|
|
\sa TQSocketNotifier
|
|
|
|
*/
|
|
|
|
|
|
|
|
int TQFile::handle() const
|
|
|
|
{
|
|
|
|
if ( !isOpen() )
|
|
|
|
return -1;
|
|
|
|
else if ( fh )
|
|
|
|
return fileno( fh );
|
|
|
|
else
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Closes an open file.
|
|
|
|
|
|
|
|
The file is not closed if it was opened with an existing file handle.
|
|
|
|
If the existing file handle is a \c FILE*, the file is flushed.
|
|
|
|
If the existing file handle is an \c int file descriptor, nothing
|
|
|
|
is done to the file.
|
|
|
|
|
|
|
|
Some "write-behind" filesystems may report an unspecified error on
|
|
|
|
closing the file. These errors only indicate that something may
|
|
|
|
have gone wrong since the previous open(). In such a case status()
|
|
|
|
reports IO_UnspecifiedError after close(), otherwise IO_Ok.
|
|
|
|
|
|
|
|
\sa open(), flush()
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
void TQFile::close()
|
|
|
|
{
|
|
|
|
bool ok = FALSE;
|
|
|
|
if ( isOpen() ) { // file is not open
|
|
|
|
if ( fh ) { // buffered file
|
|
|
|
if ( ext_f )
|
|
|
|
ok = fflush( fh ) != -1; // flush instead of closing
|
|
|
|
else
|
|
|
|
ok = fclose( fh ) != -1;
|
|
|
|
} else { // raw file
|
|
|
|
if ( ext_f )
|
|
|
|
ok = TRUE; // cannot close
|
|
|
|
else
|
|
|
|
ok = ::close( fd ) != -1;
|
|
|
|
}
|
|
|
|
init(); // restore internal state
|
|
|
|
}
|
|
|
|
if (!ok) {
|
|
|
|
setStatus( IO_UnspecifiedError );
|
|
|
|
setErrorStringErrno( errno );
|
|
|
|
}
|
|
|
|
}
|