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