Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

qfile_unix.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 ** $Id: qfile_unix.cpp,v 1.2 2003/07/10 02:40:11 llornkcor Exp $
00003 **
00004 ** Implementation of QFile class
00005 **
00006 ** Created : 950628
00007 **
00008 ** Copyright (C) 1992-2002 Trolltech AS.  All rights reserved.
00009 **
00010 ** This file is part of the tools module of the Qt GUI Toolkit.
00011 **
00012 ** This file may be distributed under the terms of the Q Public License
00013 ** as defined by Trolltech AS of Norway and appearing in the file
00014 ** LICENSE.QPL included in the packaging of this file.
00015 **
00016 ** This file may be distributed and/or modified under the terms of the
00017 ** GNU General Public License version 2 as published by the Free Software
00018 ** Foundation and appearing in the file LICENSE.GPL included in the
00019 ** packaging of this file.
00020 **
00021 ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
00022 ** licenses for Unix/X11 or for Qt/Embedded may use this file in accordance
00023 ** with the Qt Commercial License Agreement provided with the Software.
00024 **
00025 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00026 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00027 **
00028 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
00029 **   information about Qt Commercial License Agreements.
00030 ** See http://www.trolltech.com/qpl/ for QPL licensing information.
00031 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
00032 **
00033 ** Contact info@trolltech.com if any conditions of this licensing are
00034 ** not clear to you.
00035 **
00036 **********************************************************************/
00037 
00038 #include "qplatformdefs.h"
00039 
00040 // POSIX Large File Support redefines open -> open64
00041 static inline int qt_open(const char *pathname, int flags, mode_t mode)
00042 { return ::open(pathname, flags, mode); }
00043 #if defined(open)
00044 # undef open
00045 #endif
00046 
00047 // POSIX Large File Support redefines truncate -> truncate64
00048 #if defined(truncate)
00049 # undef truncate
00050 #endif
00051 
00052 #include "qfile.h"
00053 #include <errno.h>
00054 #include <limits.h>
00055 
00056 
00057 bool qt_file_access( const QString& fn, int t )
00058 {
00059     if ( fn.isEmpty() )
00060         return FALSE;
00061     return ::access( QFile::encodeName(fn), t ) == 0;
00062 }
00063 
00070 bool QFile::remove( const QString &fileName )
00071 {
00072     if ( fileName.isEmpty() ) {
00073 #if defined(QT_CHECK_NULL)
00074         qWarning( "QFile::remove: Empty or null file name" );
00075 #endif
00076         return FALSE;
00077     }
00078     return unlink( QFile::encodeName(fileName) ) == 0;
00079 }
00080 
00081 #if defined(O_NONBLOCK)
00082 # define HAS_ASYNC_FILEMODE
00083 # define OPEN_ASYNC O_NONBLOCK
00084 #elif defined(O_NDELAY)
00085 # define HAS_ASYNC_FILEMODE
00086 # define OPEN_ASYNC O_NDELAY
00087 #endif
00088 
00163 bool QFile::open( int m )
00164 {
00165     if ( isOpen() ) {                           // file already open
00166 #if defined(QT_CHECK_STATE)
00167         qWarning( "QFile::open: File already open" );
00168 #endif
00169         return FALSE;
00170     }
00171     if ( fn.isNull() ) {                        // no file name defined
00172 #if defined(QT_CHECK_NULL)
00173         qWarning( "QFile::open: No file name specified" );
00174 #endif
00175         return FALSE;
00176     }
00177     init();                                     // reset params
00178     setMode( m );
00179     if ( !(isReadable() || isWritable()) ) {
00180 #if defined(QT_CHECK_RANGE)
00181         qWarning( "QFile::open: File access not specified" );
00182 #endif
00183         return FALSE;
00184     }
00185     bool ok = TRUE;
00186     struct stat st;
00187     if ( isRaw() ) {
00188         int oflags = O_RDONLY;
00189         if ( isReadable() && isWritable() )
00190             oflags = O_RDWR;
00191         else if ( isWritable() )
00192             oflags = O_WRONLY;
00193         if ( flags() & IO_Append ) {            // append to end of file?
00194             if ( flags() & IO_Truncate )
00195                 oflags |= (O_CREAT | O_TRUNC);
00196             else
00197                 oflags |= (O_APPEND | O_CREAT);
00198             setFlags( flags() | IO_WriteOnly ); // append implies write
00199         } else if ( isWritable() ) {            // create/trunc if writable
00200             if ( flags() & IO_Truncate )
00201                 oflags |= (O_CREAT | O_TRUNC);
00202             else
00203                 oflags |= O_CREAT;
00204         }
00205 #if defined(HAS_TEXT_FILEMODE)
00206         if ( isTranslated() )
00207             oflags |= OPEN_TEXT;
00208         else
00209             oflags |= OPEN_BINARY;
00210 #endif
00211 #if defined(HAS_ASYNC_FILEMODE)
00212         if ( isAsynchronous() )
00213             oflags |= OPEN_ASYNC;
00214 #endif
00215         fd = qt_open( QFile::encodeName(fn), oflags, 0666 );
00216 
00217         if ( fd != -1 ) {                       // open successful
00218             ::fstat( fd, &st );                 // get the stat for later usage
00219         } else {
00220             ok = FALSE;
00221         }
00222     } else {                                    // buffered file I/O
00223         QCString perm;
00224         char perm2[4];
00225         bool try_create = FALSE;
00226         if ( flags() & IO_Append ) {            // append to end of file?
00227             setFlags( flags() | IO_WriteOnly ); // append implies write
00228             perm = isReadable() ? "a+" : "a";
00229         } else {
00230             if ( isReadWrite() ) {
00231                 if ( flags() & IO_Truncate ) {
00232                     perm = "w+";
00233                 } else {
00234                     perm = "r+";
00235                     try_create = TRUE;          // try to create if not exists
00236                 }
00237             } else if ( isReadable() ) {
00238                 perm = "r";
00239             } else if ( isWritable() ) {
00240                 perm = "w";
00241             }
00242         }
00243         qstrcpy( perm2, perm );
00244 #if defined(HAS_TEXT_FILEMODE)
00245         if ( isTranslated() )
00246             strcat( perm2, "t" );
00247         else
00248             strcat( perm2, "b" );
00249 #endif
00250         for (;;) { // At most twice
00251 
00252             fh = fopen( QFile::encodeName(fn), perm2 );
00253 
00254             if ( !fh && try_create ) {
00255                 perm2[0] = 'w';                 // try "w+" instead of "r+"
00256                 try_create = FALSE;
00257             } else {
00258                 break;
00259             }
00260         }
00261         if ( fh ) {
00262             ::fstat( fileno(fh), &st );         // get the stat for later usage
00263         } else {
00264             ok = FALSE;
00265         }
00266     }
00267     if ( ok ) {
00268         setState( IO_Open );
00269         // on successful open the file stat was got; now test what type
00270         // of file we have
00271         if ( (st.st_mode & S_IFMT) != S_IFREG ) {
00272             // non-seekable
00273             setType( IO_Sequential );
00274             length = INT_MAX;
00275             ioIndex = 0;
00276         } else {
00277             length = (Offset)st.st_size;
00278             ioIndex = (flags() & IO_Append) == 0 ? 0 : length;
00279             if ( !(flags()&IO_Truncate) && length == 0 && isReadable() ) {
00280                 // try if you can read from it (if you can, it's a sequential
00281                 // device; e.g. a file in the /proc filesystem)
00282                 int c = getch();
00283                 if ( c != -1 ) {
00284                     ungetch(c);
00285                     setType( IO_Sequential );
00286                     length = INT_MAX;
00287                     ioIndex = 0;
00288                 }
00289             }
00290         }
00291     } else {
00292         init();
00293         if ( errno == EMFILE )                  // no more file handles/descrs
00294             setStatus( IO_ResourceError );
00295         else
00296             setStatus( IO_OpenError );
00297     }
00298     return ok;
00299 }
00300 
00329 bool QFile::open( int m, FILE *f )
00330 {
00331     if ( isOpen() ) {
00332 #if defined(QT_CHECK_RANGE)
00333         qWarning( "QFile::open: File already open" );
00334 #endif
00335         return FALSE;
00336     }
00337     init();
00338     setMode( m &~IO_Raw );
00339     setState( IO_Open );
00340     fh = f;
00341     ext_f = TRUE;
00342     struct stat st;
00343     ::fstat( fileno(fh), &st );
00344 #if defined(QT_LARGEFILE_SUPPORT)
00345     ioIndex = (Offset)ftello( fh );
00346 #else
00347     ioIndex = (Offset)ftell( fh );
00348 #endif
00349     if ( (st.st_mode & S_IFMT) != S_IFREG || f == stdin ) { //stdin is non seekable
00350         // non-seekable
00351         setType( IO_Sequential );
00352         length = INT_MAX;
00353         ioIndex = 0;
00354     } else {
00355         length = (Offset)st.st_size;
00356         if ( !(flags()&IO_Truncate) && length == 0 && isReadable() ) {
00357             // try if you can read from it (if you can, it's a sequential
00358             // device; e.g. a file in the /proc filesystem)
00359             int c = getch();
00360             if ( c != -1 ) {
00361                 ungetch(c);
00362                 setType( IO_Sequential );
00363                 length = INT_MAX;
00364                 ioIndex = 0;
00365             }
00366         }
00367     }
00368     return TRUE;
00369 }
00370 
00391 bool QFile::open( int m, int f )
00392 {
00393     if ( isOpen() ) {
00394 #if defined(QT_CHECK_RANGE)
00395         qWarning( "QFile::open: File already open" );
00396 #endif
00397         return FALSE;
00398     }
00399     init();
00400     setMode( m |IO_Raw );
00401     setState( IO_Open );
00402     fd = f;
00403     ext_f = TRUE;
00404     struct stat st;
00405     ::fstat( fd, &st );
00406     ioIndex = (Offset)::lseek(fd, 0, SEEK_CUR);
00407     if ( (st.st_mode & S_IFMT) != S_IFREG || f == 0 ) { // stdin is not seekable...
00408         // non-seekable
00409         setType( IO_Sequential );
00410         length = INT_MAX;
00411         ioIndex = 0;
00412     } else {
00413         length = (Offset)st.st_size;
00414         if ( length == 0 && isReadable() ) {
00415             // try if you can read from it (if you can, it's a sequential
00416             // device; e.g. a file in the /proc filesystem)
00417             int c = getch();
00418             if ( c != -1 ) {
00419                 ungetch(c);
00420                 setType( IO_Sequential );
00421                 length = INT_MAX;
00422                 ioIndex = 0;
00423             }
00424             resetStatus();
00425         }
00426     }
00427     return TRUE;
00428 }
00429 
00435 QIODevice::Offset QFile::size() const
00436 {
00437     struct stat st;
00438     int ret = 0;
00439     if ( isOpen() ) {
00440         ret = ::fstat( fh ? fileno(fh) : fd, &st );
00441     } else {
00442         ret = ::stat( QFile::encodeName(fn), &st );
00443     }
00444     if ( ret == -1 )
00445         return 0;
00446 #if defined(QT_LARGEFILE_SUPPORT) && !defined(QT_ABI_64BITOFFSET)
00447     return (uint)st.st_size > UINT_MAX ? UINT_MAX : (QIODevice::Offset)st.st_size;
00448 #else
00449     return st.st_size;
00450 #endif
00451 }
00452 
00453 
00478 bool QFile::at( Offset pos )
00479 {
00480     if ( !isOpen() ) {
00481 #if defined(QT_CHECK_STATE)
00482         qWarning( "QFile::at: File is not open" );
00483 #endif
00484         return FALSE;
00485     }
00486     if ( isSequentialAccess() )
00487         return FALSE;
00488     bool ok;
00489     if ( isRaw() ) {
00490         off_t l = ::lseek( fd, pos, SEEK_SET );
00491         ok = ( l != -1 );
00492         pos = (Offset)l;
00493     } else {                                    // buffered file
00494 #if defined(QT_LARGEFILE_SUPPORT)
00495         ok = ( ::fseeko(fh, pos, SEEK_SET) == 0 );
00496 #else
00497         ok = ( ::fseek(fh, pos, SEEK_SET) == 0 );
00498 #endif
00499     }
00500     if ( ok )
00501         ioIndex = pos;
00502 #if defined(QT_CHECK_RANGE)
00503     else
00504 #if defined(QT_LARGEFILE_SUPPORT) && defined(QT_ABI_64BITOFFSET)
00505         qWarning( "QFile::at: Cannot set file position %llu", pos );
00506 #else
00507         qWarning( "QFile::at: Cannot set file position %lu", pos );
00508 #endif
00509 #endif
00510     return ok;
00511 }
00512 
00523 Q_LONG QFile::readBlock( char *p, Q_ULONG len )
00524 {
00525 #if defined(QT_CHECK_NULL)
00526     if ( !p )
00527         qWarning( "QFile::readBlock: Null pointer error" );
00528 #endif
00529 #if defined(QT_CHECK_STATE)
00530     if ( !isOpen() ) {
00531         qWarning( "QFile::readBlock: File not open" );
00532         return -1;
00533     }
00534     if ( !isReadable() ) {
00535         qWarning( "QFile::readBlock: Read operation not permitted" );
00536         return -1;
00537     }
00538 #endif
00539     Q_ULONG nread = 0;                                  // number of bytes read
00540     if ( !ungetchBuffer.isEmpty() ) {
00541         // need to add these to the returned string.
00542         uint l = ungetchBuffer.length();
00543         while( nread < l ) {
00544             *p = ungetchBuffer.at( l - nread - 1 );
00545             p++;
00546             nread++;
00547         }
00548         ungetchBuffer.truncate( l - nread );
00549     }
00550 
00551     if ( nread < len ) {
00552         if ( isRaw() ) {                                // raw file
00553             nread += ::read( fd, p, len-nread );
00554             if ( len && nread <= 0 ) {
00555                 nread = 0;
00556                 setStatus(IO_ReadError);
00557             }
00558         } else {                                        // buffered file
00559             nread += fread( p, 1, len-nread, fh );
00560             if ( (uint)nread != len ) {
00561                 if ( ferror( fh ) || nread==0 )
00562                     setStatus(IO_ReadError);
00563             }
00564         }
00565     }
00566     if ( !isSequentialAccess() )
00567         ioIndex += nread;
00568     return nread;
00569 }
00570 
00571 
00586 Q_LONG QFile::writeBlock( const char *p, Q_ULONG len )
00587 {
00588 #if defined(QT_CHECK_NULL)
00589     if ( p == 0 && len != 0 )
00590         qWarning( "QFile::writeBlock: Null pointer error" );
00591 #endif
00592 #if defined(QT_CHECK_STATE)
00593     if ( !isOpen() ) {                          // file not open
00594         qWarning( "QFile::writeBlock: File not open" );
00595         return -1;
00596     }
00597     if ( !isWritable() ) {                      // writing not permitted
00598         qWarning( "QFile::writeBlock: Write operation not permitted" );
00599         return -1;
00600     }
00601 #endif
00602     Q_ULONG nwritten;                           // number of bytes written
00603     if ( isRaw() )                              // raw file
00604         nwritten = ::write( fd, (void *)p, len );
00605     else                                        // buffered file
00606         nwritten = fwrite( p, 1, len, fh );
00607     if ( nwritten != len ) {            // write error
00608         if ( errno == ENOSPC )                  // disk is full
00609             setStatus( IO_ResourceError );
00610         else
00611             setStatus( IO_WriteError );
00612         if ( !isSequentialAccess() ) {
00613             if ( isRaw() )                      // recalc file position
00614                 ioIndex = (Offset)::lseek( fd, 0, SEEK_CUR );
00615             else
00616 #if defined(QT_LARGEFILE_SUPPORT)
00617                 ioIndex = (Offset)::fseeko( fh, 0, SEEK_CUR );
00618 #else
00619                 ioIndex = (Offset)::fseek( fh, 0, SEEK_CUR );
00620 #endif
00621         }
00622     } else {
00623         if ( !isSequentialAccess() )
00624             ioIndex += nwritten;
00625     }
00626     if ( ioIndex > length )                     // update file length
00627         length = ioIndex;
00628     return nwritten;
00629 }
00630 
00644 int QFile::handle() const
00645 {
00646     if ( !isOpen() )
00647         return -1;
00648     else if ( fh )
00649         return fileno( fh );
00650     else
00651         return fd;
00652 }
00653 
00671 void QFile::close()
00672 {
00673     bool ok = FALSE;
00674     if ( isOpen() ) {                           // file is not open
00675         if ( fh ) {                             // buffered file
00676             if ( ext_f )
00677                 ok = fflush( fh ) != -1;        // flush instead of closing
00678             else
00679                 ok = fclose( fh ) != -1;
00680         } else {                                // raw file
00681             if ( ext_f )
00682                 ok = TRUE;                      // cannot close
00683             else
00684                 ok = ::close( fd ) != -1;
00685         }
00686         init();                                 // restore internal state
00687     }
00688     if (!ok)
00689         setStatus( IO_UnspecifiedError );
00690 
00691     return;
00692 }

Generated on Sat Nov 5 16:18:30 2005 for OPIE by  doxygen 1.4.2