Orb/Doxygen/qtools/qfile_unix.cpp
changeset 0 42188c7ea2d9
equal deleted inserted replaced
-1:000000000000 0:42188c7ea2d9
       
     1 /****************************************************************************
       
     2 ** 
       
     3 **
       
     4 ** Implementation of QFileInfo class
       
     5 **
       
     6 ** Created : 950628
       
     7 **
       
     8 ** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
       
     9 **
       
    10 ** This file is part of the tools module of the Qt GUI Toolkit.
       
    11 **
       
    12 ** This file may be distributed under the terms of the Q Public License
       
    13 ** as defined by Trolltech AS of Norway and appearing in the file
       
    14 ** LICENSE.QPL included in the packaging of this file.
       
    15 **
       
    16 ** This file may be distributed and/or modified under the terms of the
       
    17 ** GNU General Public License version 2 as published by the Free Software
       
    18 ** Foundation and appearing in the file LICENSE.GPL included in the
       
    19 ** packaging of this file.
       
    20 **
       
    21 ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
       
    22 ** licenses for Unix/X11 or for Qt/Embedded may use this file in accordance
       
    23 ** with the Qt Commercial License Agreement provided with the Software.
       
    24 **
       
    25 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
       
    26 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
       
    27 **
       
    28 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
       
    29 **   information about Qt Commercial License Agreements.
       
    30 ** See http://www.trolltech.com/qpl/ for QPL licensing information.
       
    31 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
       
    32 **
       
    33 ** Contact info@trolltech.com if any conditions of this licensing are
       
    34 ** not clear to you.
       
    35 **
       
    36 **********************************************************************/
       
    37 
       
    38 #include "qglobal.h"
       
    39 
       
    40 #include "qfile.h"
       
    41 #include "qfiledefs_p.h"
       
    42 
       
    43 #if (defined(_OS_MAC_) && (!defined(_OS_UNIX_))) || defined(_OS_MSDOS_) || defined(_OS_WIN32_) || defined(_OS_OS2_) || defined(_OS_CYGWIN_)
       
    44 # define HAS_TEXT_FILEMODE			// has translate/text filemode
       
    45 #endif
       
    46 #if defined(O_NONBLOCK)
       
    47 # define HAS_ASYNC_FILEMODE
       
    48 # define OPEN_ASYNC O_NONBLOCK
       
    49 #elif defined(O_NDELAY)
       
    50 # define HAS_ASYNC_FILEMODE
       
    51 # define OPEN_ASYNC O_NDELAY
       
    52 #endif
       
    53 
       
    54 bool qt_file_access( const QString& fn, int t )
       
    55 {
       
    56     if ( fn.isEmpty() )
       
    57 	return FALSE;
       
    58     return ACCESS( QFile::encodeName(fn), t ) == 0;
       
    59 }
       
    60 
       
    61 /*!
       
    62   Removes the file \a fileName.
       
    63   Returns TRUE if successful, otherwise FALSE.
       
    64 */
       
    65 
       
    66 bool QFile::remove( const QString &fileName )
       
    67 {
       
    68     if ( fileName.isEmpty() ) {
       
    69 #if defined(CHECK_NULL)
       
    70 	qWarning( "QFile::remove: Empty or null file name" );
       
    71 #endif
       
    72 	return FALSE;
       
    73     }
       
    74     return unlink( QFile::encodeName(fileName) ) == 0;	
       
    75     // unlink more common in UNIX
       
    76 }
       
    77 
       
    78 #if defined(O_NONBLOCK)
       
    79 # define HAS_ASYNC_FILEMODE
       
    80 # define OPEN_ASYNC O_NONBLOCK
       
    81 #elif defined(O_NDELAY)
       
    82 # define HAS_ASYNC_FILEMODE
       
    83 # define OPEN_ASYNC O_NDELAY
       
    84 #endif
       
    85 
       
    86 /*!
       
    87   Opens the file specified by the file name currently set, using the mode \e m.
       
    88   Returns TRUE if successful, otherwise FALSE.
       
    89 
       
    90   The mode parameter \e m must be a combination of the following flags:
       
    91   <ul>
       
    92   <li>\c IO_Raw specified raw (non-buffered) file access.
       
    93   <li>\c IO_ReadOnly opens the file in read-only mode.
       
    94   <li>\c IO_WriteOnly opens the file in write-only mode (and truncates).
       
    95   <li>\c IO_ReadWrite opens the file in read/write mode, equivalent to
       
    96   \c (IO_ReadOnly|IO_WriteOnly).
       
    97   <li>\c IO_Append opens the file in append mode. This mode is very useful
       
    98   when you want to write something to a log file. The file index is set to
       
    99   the end of the file. Note that the result is undefined if you position the
       
   100   file index manually using at() in append mode.
       
   101   <li>\c IO_Truncate truncates the file.
       
   102   <li>\c IO_Translate enables carriage returns and linefeed translation
       
   103   for text files under MS-DOS, Windows and OS/2.
       
   104   </ul>
       
   105 
       
   106   The raw access mode is best when I/O is block-operated using 4kB block size
       
   107   or greater. Buffered access works better when reading small portions of
       
   108   data at a time.
       
   109 
       
   110   <strong>Important:</strong> When working with buffered files, data may
       
   111   not be written to the file at once. Call \link flush() flush\endlink
       
   112   to make sure the data is really written.
       
   113 
       
   114   \warning We have experienced problems with some C libraries when a buffered
       
   115   file is opened for both reading and writing. If a read operation takes place
       
   116   immediately after a write operation, the read buffer contains garbage data.
       
   117   Worse, the same garbage is written to the file. Calling flush() before
       
   118   readBlock() solved this problem.
       
   119 
       
   120   If the file does not exist and \c IO_WriteOnly or \c IO_ReadWrite is
       
   121   specified, it is created.
       
   122 
       
   123   Example:
       
   124   \code
       
   125     QFile f1( "/tmp/data.bin" );
       
   126     QFile f2( "readme.txt" );
       
   127     f1.open( IO_Raw | IO_ReadWrite | IO_Append );
       
   128     f2.open( IO_ReadOnly | IO_Translate );
       
   129   \endcode
       
   130 
       
   131   \sa name(), close(), isOpen(), flush()
       
   132 */
       
   133 
       
   134 bool QFile::open( int m )
       
   135 {
       
   136     if ( isOpen() ) {				// file already open
       
   137 #if defined(CHECK_STATE)
       
   138 	qWarning( "QFile::open: File already open" );
       
   139 #endif
       
   140 	return FALSE;
       
   141     }
       
   142     if ( fn.isNull() ) {			// no file name defined
       
   143 #if defined(CHECK_NULL)
       
   144 	qWarning( "QFile::open: No file name specified" );
       
   145 #endif
       
   146 	return FALSE;
       
   147     }
       
   148     init();					// reset params
       
   149     setMode( m );
       
   150     if ( !(isReadable() || isWritable()) ) {
       
   151 #if defined(CHECK_RANGE)
       
   152 	qWarning( "QFile::open: File access not specified" );
       
   153 #endif
       
   154 	return FALSE;
       
   155     }
       
   156     bool ok = TRUE;
       
   157     STATBUF st;
       
   158     if ( isRaw() ) {				// raw file I/O
       
   159 	int oflags = OPEN_RDONLY;
       
   160 	if ( isReadable() && isWritable() )
       
   161 	    oflags = OPEN_RDWR;
       
   162 	else if ( isWritable() )
       
   163 	    oflags = OPEN_WRONLY;
       
   164 	if ( flags() & IO_Append ) {		// append to end of file?
       
   165 	    if ( flags() & IO_Truncate )
       
   166 		oflags |= (OPEN_CREAT | OPEN_TRUNC);
       
   167 	    else
       
   168 		oflags |= (OPEN_APPEND | OPEN_CREAT);
       
   169 	    setFlags( flags() | IO_WriteOnly ); // append implies write
       
   170 	} else if ( isWritable() ) {		// create/trunc if writable
       
   171 	    if ( flags() & IO_Truncate )
       
   172 		oflags |= (OPEN_CREAT | OPEN_TRUNC);
       
   173 	    else
       
   174 		oflags |= OPEN_CREAT;
       
   175 	}
       
   176 #if defined(HAS_TEXT_FILEMODE)
       
   177 	if ( isTranslated() )
       
   178 #ifdef __CYGWIN__
       
   179           /* Do nothing, allowing the Cygwin mount mode to take effect. */;
       
   180 #else
       
   181 	    oflags |= OPEN_TEXT;
       
   182 #endif
       
   183 	else
       
   184 	    oflags |= OPEN_BINARY;
       
   185 #endif
       
   186 #if defined(HAS_ASYNC_FILEMODE)
       
   187 	if ( isAsynchronous() )
       
   188 	    oflags |= OPEN_ASYNC;
       
   189 #endif
       
   190 	fd = OPEN( QFile::encodeName(fn), oflags, 0666 );
       
   191 
       
   192 	if ( fd != -1 ) {			// open successful
       
   193 	    FSTAT( fd, &st ); // get the stat for later usage
       
   194 	} else {
       
   195 	    ok = FALSE;
       
   196 	}
       
   197     } else {					// buffered file I/O
       
   198 	QCString perm;
       
   199 	char perm2[4];
       
   200 	bool try_create = FALSE;
       
   201 	if ( flags() & IO_Append ) {		// append to end of file?
       
   202 	    setFlags( flags() | IO_WriteOnly ); // append implies write
       
   203 	    perm = isReadable() ? "a+" : "a";
       
   204 	} else {
       
   205 	    if ( isReadWrite() ) {
       
   206 		if ( flags() & IO_Truncate ) {
       
   207 		    perm = "w+";
       
   208 		} else {
       
   209 		    perm = "r+";
       
   210 		    try_create = TRUE;		// try to create if not exists
       
   211 		}
       
   212 	    } else if ( isReadable() ) {
       
   213 		perm = "r";
       
   214 	    } else if ( isWritable() ) {
       
   215 		perm = "w";
       
   216 	    }
       
   217 	}
       
   218 	qstrcpy( perm2, perm );
       
   219 #if defined(HAS_TEXT_FILEMODE)
       
   220 	if ( isTranslated() )
       
   221 #ifdef __CYGWIN__
       
   222             /* Do nothing, allowing the Cygwin mount mode to take effect. */;
       
   223 #else
       
   224 	    strcat( perm2, "t" );
       
   225 #endif
       
   226 	else
       
   227 	    strcat( perm2, "b" );
       
   228 #endif
       
   229 	while (1) { // At most twice
       
   230 
       
   231 	    fh = fopen( QFile::encodeName(fn), perm2 );
       
   232 
       
   233 	    if ( !fh && try_create ) {
       
   234 		perm2[0] = 'w';			// try "w+" instead of "r+"
       
   235 		try_create = FALSE;
       
   236 	    } else {
       
   237 		break;
       
   238 	    }
       
   239 	}
       
   240 	if ( fh ) {
       
   241 	    FSTAT( FILENO(fh), &st ); // get the stat for later usage
       
   242 	} else {
       
   243 	    ok = FALSE;
       
   244 	}
       
   245     }
       
   246     if ( ok ) {
       
   247 	setState( IO_Open );
       
   248 	// on successful open the file stat was got; now test what type
       
   249 	// of file we have
       
   250 	if ( (st.st_mode & STAT_MASK) != STAT_REG ) {
       
   251 	    // non-seekable
       
   252 	    setType( IO_Sequential );
       
   253 	    length = INT_MAX;
       
   254 	    ioIndex  = (flags() & IO_Append) == 0 ? 0 : length;
       
   255 	} else {
       
   256 	    length = (int)st.st_size;
       
   257 	    ioIndex  = (flags() & IO_Append) == 0 ? 0 : length;
       
   258 	    if ( !(flags()&IO_Truncate) && length == 0 && isReadable() ) {
       
   259 		// try if you can read from it (if you can, it's a sequential
       
   260 		// device; e.g. a file in the /proc filesystem)
       
   261 		int c = getch();
       
   262 		if ( c != -1 ) {
       
   263 		    ungetch(c);
       
   264 		    setType( IO_Sequential );
       
   265 		    length = INT_MAX;
       
   266 		}
       
   267 	    }
       
   268 	}
       
   269     } else {
       
   270 	init();
       
   271 	if ( errno == EMFILE )			// no more file handles/descrs
       
   272 	    setStatus( IO_ResourceError );
       
   273 	else
       
   274 	    setStatus( IO_OpenError );
       
   275     }
       
   276     return ok;
       
   277 }
       
   278 
       
   279 /*!
       
   280   Opens a file in the mode \e m using an existing file handle \e f.
       
   281   Returns TRUE if successful, otherwise FALSE.
       
   282 
       
   283   Example:
       
   284   \code
       
   285     #include <stdio.h>
       
   286 
       
   287     void printError( const char* msg )
       
   288     {
       
   289 	QFile f;
       
   290 	f.open( IO_WriteOnly, stderr );
       
   291 	f.writeBlock( msg, qstrlen(msg) );	// write to stderr
       
   292 	f.close();
       
   293     }
       
   294   \endcode
       
   295 
       
   296   When a QFile is opened using this function, close() does not actually
       
   297   close the file, only flushes it.
       
   298 
       
   299   \warning If \e f is \c stdin, \c stdout, \c stderr, you may not
       
   300   be able to seek.  See QIODevice::isSequentialAccess() for more
       
   301   information.
       
   302 
       
   303   \sa close()
       
   304 */
       
   305 
       
   306 bool QFile::open( int m, FILE *f )
       
   307 {
       
   308     if ( isOpen() ) {
       
   309 #if defined(CHECK_RANGE)
       
   310 	qWarning( "QFile::open: File already open" );
       
   311 #endif
       
   312 	return FALSE;
       
   313     }
       
   314     init();
       
   315     setMode( m &~IO_Raw );
       
   316     setState( IO_Open );
       
   317     fh = f;
       
   318     ext_f = TRUE;
       
   319     STATBUF st;
       
   320     FSTAT( FILENO(fh), &st );
       
   321     ioIndex = (int)ftell( fh );
       
   322     if ( (st.st_mode & STAT_MASK) != STAT_REG || f == stdin ) { //stdin is non seekable
       
   323 	// non-seekable
       
   324 	setType( IO_Sequential );
       
   325 	length = INT_MAX;
       
   326     } else {
       
   327 	length = (int)st.st_size;
       
   328 	if ( !(flags()&IO_Truncate) && length == 0 && isReadable() ) {
       
   329 	    // try if you can read from it (if you can, it's a sequential
       
   330 	    // device; e.g. a file in the /proc filesystem)
       
   331 	    int c = getch();
       
   332 	    if ( c != -1 ) {
       
   333 		ungetch(c);
       
   334 		setType( IO_Sequential );
       
   335 		length = INT_MAX;
       
   336 	    }
       
   337 	}
       
   338     }
       
   339     return TRUE;
       
   340 }
       
   341 
       
   342 /*!
       
   343   Opens a file in the mode \e m using an existing file descriptor \e f.
       
   344   Returns TRUE if successful, otherwise FALSE.
       
   345 
       
   346   When a QFile is opened using this function, close() does not actually
       
   347   close the file.
       
   348 
       
   349   \warning If \e f is one of 0 (stdin), 1 (stdout) or 2 (stderr), you may not
       
   350   be able to seek. size() is set to \c INT_MAX (in limits.h).
       
   351 
       
   352   \sa close()
       
   353 */
       
   354 
       
   355 
       
   356 bool QFile::open( int m, int f )
       
   357 {
       
   358     if ( isOpen() ) {
       
   359 #if defined(CHECK_RANGE)
       
   360 	qWarning( "QFile::open: File already open" );
       
   361 #endif
       
   362 	return FALSE;
       
   363     }
       
   364     init();
       
   365     setMode( m |IO_Raw );
       
   366     setState( IO_Open );
       
   367     fd = f;
       
   368     ext_f = TRUE;
       
   369     STATBUF st;
       
   370     FSTAT( fd, &st );
       
   371     ioIndex  = (int)LSEEK(fd, 0, SEEK_CUR);
       
   372     if ( (st.st_mode & STAT_MASK) != STAT_REG || f == 0 ) { // stdin is not seekable...
       
   373 	// non-seekable
       
   374 	setType( IO_Sequential );
       
   375 	length = INT_MAX;
       
   376     } else {
       
   377 	length = (int)st.st_size;
       
   378 	if ( length == 0 && isReadable() ) {
       
   379 	    // try if you can read from it (if you can, it's a sequential
       
   380 	    // device; e.g. a file in the /proc filesystem)
       
   381 	    int c = getch();
       
   382 	    if ( c != -1 ) {
       
   383 		ungetch(c);
       
   384 		setType( IO_Sequential );
       
   385 		length = INT_MAX;
       
   386 	    }
       
   387 	    resetStatus();
       
   388 	}
       
   389     }
       
   390     return TRUE;
       
   391 }
       
   392 
       
   393 /*!
       
   394   Returns the file size.
       
   395   \sa at()
       
   396 */
       
   397 
       
   398 uint QFile::size() const
       
   399 {
       
   400     STATBUF st;
       
   401     if ( isOpen() ) {
       
   402 	FSTAT( fh ? FILENO(fh) : fd, &st );
       
   403     } else {
       
   404 	STAT( QFile::encodeName(fn), &st );
       
   405     }
       
   406     return st.st_size;
       
   407 }
       
   408 
       
   409 /*!
       
   410   \fn int QFile::at() const
       
   411   Returns the file index.
       
   412   \sa size()
       
   413 */
       
   414 
       
   415 /*!
       
   416   Sets the file index to \e pos. Returns TRUE if successful, otherwise FALSE.
       
   417 
       
   418   Example:
       
   419   \code
       
   420     QFile f( "data.bin" );
       
   421     f.open( IO_ReadOnly );			// index set to 0
       
   422     f.at( 100 );				// set index to 100
       
   423     f.at( f.at()+50 );				// set index to 150
       
   424     f.at( f.size()-80 );			// set index to 80 before EOF
       
   425     f.close();
       
   426   \endcode
       
   427 
       
   428   \warning The result is undefined if the file was \link open() opened\endlink
       
   429   using the \c IO_Append specifier.
       
   430 
       
   431   \sa size(), open()
       
   432 */
       
   433 
       
   434 bool QFile::at( int pos )
       
   435 {
       
   436     if ( !isOpen() ) {
       
   437 #if defined(CHECK_STATE)
       
   438 	qWarning( "QFile::at: File is not open" );
       
   439 #endif
       
   440 	return FALSE;
       
   441     }
       
   442     bool ok;
       
   443     if ( isRaw() ) {				// raw file
       
   444 	pos = (int)LSEEK(fd, pos, SEEK_SET);
       
   445 	ok = pos != -1;
       
   446     } else {					// buffered file
       
   447 	ok = fseek(fh, pos, SEEK_SET) == 0;
       
   448     }
       
   449     if ( ok )
       
   450 	ioIndex = pos;
       
   451 #if defined(CHECK_RANGE)
       
   452     else
       
   453 	qWarning( "QFile::at: Cannot set file position %d", pos );
       
   454 #endif
       
   455     return ok;
       
   456 }
       
   457 
       
   458 /*!
       
   459   Reads at most \e len bytes from the file into \e p and returns the
       
   460   number of bytes actually read.
       
   461 
       
   462   Returns -1 if a serious error occurred.
       
   463 
       
   464   \warning We have experienced problems with some C libraries when a buffered
       
   465   file is opened for both reading and writing. If a read operation takes place
       
   466   immediately after a write operation, the read buffer contains garbage data.
       
   467   Worse, the same garbage is written to the file. Calling flush() before
       
   468   readBlock() solved this problem.
       
   469 
       
   470   \sa writeBlock()
       
   471 */
       
   472 
       
   473 int QFile::readBlock( char *p, uint len )
       
   474 {
       
   475 #if defined(CHECK_NULL)
       
   476     if ( !p )
       
   477 	qWarning( "QFile::readBlock: Null pointer error" );
       
   478 #endif
       
   479 #if defined(CHECK_STATE)
       
   480     if ( !isOpen() ) {				// file not open
       
   481 	qWarning( "QFile::readBlock: File not open" );
       
   482 	return -1;
       
   483     }
       
   484     if ( !isReadable() ) {			// reading not permitted
       
   485 	qWarning( "QFile::readBlock: Read operation not permitted" );
       
   486 	return -1;
       
   487     }
       
   488 #endif
       
   489     int nread = 0;					// number of bytes read
       
   490     if ( !ungetchBuffer.isEmpty() ) {
       
   491 	// need to add these to the returned string.
       
   492 	int l = ungetchBuffer.length();
       
   493 	while( nread < l ) {
       
   494 	    *p = ungetchBuffer[ l - nread - 1 ];
       
   495 	    p++;
       
   496 	    nread++;
       
   497 	}
       
   498 	ungetchBuffer.truncate( l - nread );
       
   499     }
       
   500     
       
   501     if ( nread < (int)len ) {
       
   502 	if ( isRaw() ) {				// raw file
       
   503 	    nread += READ( fd, p, len-nread );
       
   504 	    if ( len && nread <= 0 ) {
       
   505 		nread = 0;
       
   506 		setStatus(IO_ReadError);
       
   507 	    }
       
   508 	} else {					// buffered file
       
   509 	    nread += fread( p, 1, len-nread, fh );
       
   510 	    if ( (uint)nread != len ) {
       
   511 		if ( ferror( fh ) || nread==0 )
       
   512 		    setStatus(IO_ReadError);
       
   513 	    }
       
   514 	}
       
   515     }
       
   516     ioIndex += nread;
       
   517     return nread;
       
   518 }
       
   519 
       
   520 /*! \overload int writeBlock( const QByteArray& data )
       
   521 */
       
   522 
       
   523 /*! \reimp
       
   524 
       
   525   Writes \e len bytes from \e p to the file and returns the number of
       
   526   bytes actually written.
       
   527 
       
   528   Returns -1 if a serious error occurred.
       
   529 
       
   530   \warning When working with buffered files, data may not be written
       
   531   to the file at once. Call flush() to make sure the data is really
       
   532   written.
       
   533 
       
   534   \sa readBlock()
       
   535 */
       
   536 
       
   537 int QFile::writeBlock( const char *p, uint len )
       
   538 {
       
   539 #if defined(CHECK_NULL)
       
   540     if ( p == 0 && len != 0 )
       
   541 	qWarning( "QFile::writeBlock: Null pointer error" );
       
   542 #endif
       
   543 #if defined(CHECK_STATE)
       
   544     if ( !isOpen() ) {				// file not open
       
   545 	qWarning( "QFile::writeBlock: File not open" );
       
   546 	return -1;
       
   547     }
       
   548     if ( !isWritable() ) {			// writing not permitted
       
   549 	qWarning( "QFile::writeBlock: Write operation not permitted" );
       
   550 	return -1;
       
   551     }
       
   552 #endif
       
   553     int nwritten;				// number of bytes written
       
   554     if ( isRaw() )				// raw file
       
   555 	nwritten = WRITE( fd, p, len );
       
   556     else					// buffered file
       
   557 	nwritten = fwrite( p, 1, len, fh );
       
   558     if ( nwritten != (int)len ) {		// write error
       
   559 	if ( errno == ENOSPC )			// disk is full
       
   560 	    setStatus( IO_ResourceError );
       
   561 	else
       
   562 	    setStatus( IO_WriteError );
       
   563 	if ( isRaw() )				// recalc file position
       
   564 	    ioIndex = (int)LSEEK( fd, 0, SEEK_CUR );
       
   565 	else
       
   566 	    ioIndex = fseek( fh, 0, SEEK_CUR );
       
   567     } else {
       
   568 	ioIndex += nwritten;
       
   569     }
       
   570     if ( ioIndex > length )			// update file length
       
   571 	length = ioIndex;
       
   572     return nwritten;
       
   573 }
       
   574 
       
   575 /*!
       
   576   Returns the file handle of the file.
       
   577 
       
   578   This is a small positive integer, suitable for use with C library
       
   579   functions such as fdopen() and fcntl(), as well as with QSocketNotifier.
       
   580 
       
   581   If the file is not open or there is an error, handle() returns -1.
       
   582 
       
   583   \sa QSocketNotifier
       
   584 */
       
   585 
       
   586 int QFile::handle() const
       
   587 {
       
   588     if ( !isOpen() )
       
   589 	return -1;
       
   590     else if ( fh )
       
   591 	return FILENO( fh );
       
   592     else
       
   593 	return fd;
       
   594 }
       
   595 
       
   596 /*!
       
   597   Closes an open file.
       
   598 
       
   599   The file is not closed if it was opened with an existing file handle.
       
   600   If the existing file handle is a \c FILE*, the file is flushed.
       
   601   If the existing file handle is an \c int file descriptor, nothing
       
   602   is done to the file.
       
   603 
       
   604   Some "write-behind" filesystems may report an unspecified error on
       
   605   closing the file. These errors only indicate that something may
       
   606   have gone wrong since the previous open(). In such a case status()
       
   607   reports IO_UnspecifiedError after close(), otherwise IO_Ok.
       
   608 
       
   609   \sa open(), flush()
       
   610 */
       
   611 
       
   612 
       
   613 void QFile::close()
       
   614 {
       
   615     bool ok = FALSE;
       
   616     if ( isOpen() ) {				// file is not open
       
   617 	if ( fh ) {				// buffered file
       
   618 	    if ( ext_f )
       
   619 		ok = fflush( fh ) != -1;	// flush instead of closing
       
   620 	    else
       
   621 		ok = fclose( fh ) != -1;
       
   622 	} else {				// raw file
       
   623 	    if ( ext_f )
       
   624 		ok = TRUE;			// cannot close
       
   625 	    else
       
   626 		ok = CLOSE( fd ) != -1;
       
   627 	}
       
   628 	init();					// restore internal state
       
   629     }
       
   630     if (!ok)
       
   631 	setStatus (IO_UnspecifiedError);
       
   632 
       
   633     return;
       
   634 }
       
   635 
       
   636 int64 QFile::pos() const
       
   637 {
       
   638   if (isOpen())
       
   639   {
       
   640     // TODO: support 64 bit size
       
   641     return ftell( fh );
       
   642   }
       
   643   return -1;
       
   644 }
       
   645 
       
   646 int64 QFile::toEnd() 
       
   647 {
       
   648   if (isOpen())
       
   649   {
       
   650      // TODO: support 64 bit size
       
   651      if (fseek( fh, 0, SEEK_END )!=-1)
       
   652      {
       
   653        return ftell( fh );
       
   654      }
       
   655   }
       
   656   return -1;
       
   657 }
       
   658 
       
   659 bool QFile::seek( int64 pos )
       
   660 {
       
   661   if (isOpen())
       
   662   {
       
   663     // TODO: support 64 bit size
       
   664     return fseek( fh, pos, SEEK_SET )!=-1;
       
   665   }
       
   666   return FALSE;
       
   667 }
       
   668