Chameleon

Chameleon Svn Source Tree

Root/branches/xZenu/src/util/doxygen/qtools/qfile_unix.cpp

Source at commit 1322 created 9 years 5 months ago.
By meklort, Add doxygen to utils folder
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
54bool qt_file_access( const QString& fn, int t )
55{
56 if ( fn.isEmpty() )
57return 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
66bool QFile::remove( const QString &fileName )
67{
68 if ( fileName.isEmpty() ) {
69#if defined(CHECK_NULL)
70qWarning( "QFile::remove: Empty or null file name" );
71#endif
72return 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
134bool QFile::open( int m )
135{
136 if ( isOpen() ) {// file already open
137#if defined(CHECK_STATE)
138qWarning( "QFile::open: File already open" );
139#endif
140return FALSE;
141 }
142 if ( fn.isNull() ) {// no file name defined
143#if defined(CHECK_NULL)
144qWarning( "QFile::open: No file name specified" );
145#endif
146return FALSE;
147 }
148 init();// reset params
149 setMode( m );
150 if ( !(isReadable() || isWritable()) ) {
151#if defined(CHECK_RANGE)
152qWarning( "QFile::open: File access not specified" );
153#endif
154return FALSE;
155 }
156 bool ok = TRUE;
157 STATBUF st;
158 if ( isRaw() ) {// raw file I/O
159int oflags = OPEN_RDONLY;
160if ( isReadable() && isWritable() )
161 oflags = OPEN_RDWR;
162else if ( isWritable() )
163 oflags = OPEN_WRONLY;
164if ( flags() & IO_Append ) {// append to end of file?
165 if ( flags() & IO_Truncate )
166oflags |= (OPEN_CREAT | OPEN_TRUNC);
167 else
168oflags |= (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 )
172oflags |= (OPEN_CREAT | OPEN_TRUNC);
173 else
174oflags |= OPEN_CREAT;
175}
176#if defined(HAS_TEXT_FILEMODE)
177if ( isTranslated() )
178#ifdef __CYGWIN__
179 /* Do nothing, allowing the Cygwin mount mode to take effect. */;
180#else
181 oflags |= OPEN_TEXT;
182#endif
183else
184 oflags |= OPEN_BINARY;
185#endif
186#if defined(HAS_ASYNC_FILEMODE)
187if ( isAsynchronous() )
188 oflags |= OPEN_ASYNC;
189#endif
190fd = OPEN( QFile::encodeName(fn), oflags, 0666 );
191
192if ( 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
198QCString perm;
199char perm2[4];
200bool try_create = FALSE;
201if ( 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() ) {
206if ( 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() ) {
213perm = "r";
214 } else if ( isWritable() ) {
215perm = "w";
216 }
217}
218qstrcpy( perm2, perm );
219#if defined(HAS_TEXT_FILEMODE)
220if ( isTranslated() )
221#ifdef __CYGWIN__
222 /* Do nothing, allowing the Cygwin mount mode to take effect. */;
223#else
224 strcat( perm2, "t" );
225#endif
226else
227 strcat( perm2, "b" );
228#endif
229while (1) { // At most twice
230
231 fh = fopen( QFile::encodeName(fn), perm2 );
232
233 if ( !fh && try_create ) {
234perm2[0] = 'w';// try "w+" instead of "r+"
235try_create = FALSE;
236 } else {
237break;
238 }
239}
240if ( fh ) {
241 FSTAT( FILENO(fh), &st ); // get the stat for later usage
242} else {
243 ok = FALSE;
244}
245 }
246 if ( ok ) {
247setState( IO_Open );
248// on successful open the file stat was got; now test what type
249// of file we have
250if ( (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)
261int c = getch();
262if ( c != -1 ) {
263 ungetch(c);
264 setType( IO_Sequential );
265 length = INT_MAX;
266}
267 }
268}
269 } else {
270init();
271if ( errno == EMFILE )// no more file handles/descrs
272 setStatus( IO_ResourceError );
273else
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 {
289QFile f;
290f.open( IO_WriteOnly, stderr );
291f.writeBlock( msg, qstrlen(msg) );// write to stderr
292f.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
306bool QFile::open( int m, FILE *f )
307{
308 if ( isOpen() ) {
309#if defined(CHECK_RANGE)
310qWarning( "QFile::open: File already open" );
311#endif
312return 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
324setType( IO_Sequential );
325length = INT_MAX;
326 } else {
327length = (int)st.st_size;
328if ( !(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 ) {
333ungetch(c);
334setType( IO_Sequential );
335length = 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
356bool QFile::open( int m, int f )
357{
358 if ( isOpen() ) {
359#if defined(CHECK_RANGE)
360qWarning( "QFile::open: File already open" );
361#endif
362return 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
374setType( IO_Sequential );
375length = INT_MAX;
376 } else {
377length = (int)st.st_size;
378if ( 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 ) {
383ungetch(c);
384setType( IO_Sequential );
385length = INT_MAX;
386 }
387 resetStatus();
388}
389 }
390 return TRUE;
391}
392
393/*!
394 Returns the file size.
395 \sa at()
396*/
397
398uint QFile::size() const
399{
400 STATBUF st;
401 if ( isOpen() ) {
402FSTAT( fh ? FILENO(fh) : fd, &st );
403 } else {
404STAT( 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
434bool QFile::at( int pos )
435{
436 if ( !isOpen() ) {
437#if defined(CHECK_STATE)
438qWarning( "QFile::at: File is not open" );
439#endif
440return FALSE;
441 }
442 bool ok;
443 if ( isRaw() ) {// raw file
444pos = (int)LSEEK(fd, pos, SEEK_SET);
445ok = pos != -1;
446 } else {// buffered file
447ok = fseek(fh, pos, SEEK_SET) == 0;
448 }
449 if ( ok )
450ioIndex = pos;
451#if defined(CHECK_RANGE)
452 else
453qWarning( "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
473int QFile::readBlock( char *p, uint len )
474{
475#if defined(CHECK_NULL)
476 if ( !p )
477qWarning( "QFile::readBlock: Null pointer error" );
478#endif
479#if defined(CHECK_STATE)
480 if ( !isOpen() ) {// file not open
481qWarning( "QFile::readBlock: File not open" );
482return -1;
483 }
484 if ( !isReadable() ) {// reading not permitted
485qWarning( "QFile::readBlock: Read operation not permitted" );
486return -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.
492int l = ungetchBuffer.length();
493while( nread < l ) {
494 *p = ungetchBuffer[ l - nread - 1 ];
495 p++;
496 nread++;
497}
498ungetchBuffer.truncate( l - nread );
499 }
500
501 if ( nread < (int)len ) {
502if ( isRaw() ) {// raw file
503 nread += READ( fd, p, len-nread );
504 if ( len && nread <= 0 ) {
505nread = 0;
506setStatus(IO_ReadError);
507 }
508} else {// buffered file
509 nread += fread( p, 1, len-nread, fh );
510 if ( (uint)nread != len ) {
511if ( 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
537int QFile::writeBlock( const char *p, uint len )
538{
539#if defined(CHECK_NULL)
540 if ( p == 0 && len != 0 )
541qWarning( "QFile::writeBlock: Null pointer error" );
542#endif
543#if defined(CHECK_STATE)
544 if ( !isOpen() ) {// file not open
545qWarning( "QFile::writeBlock: File not open" );
546return -1;
547 }
548 if ( !isWritable() ) {// writing not permitted
549qWarning( "QFile::writeBlock: Write operation not permitted" );
550return -1;
551 }
552#endif
553 int nwritten;// number of bytes written
554 if ( isRaw() )// raw file
555nwritten = WRITE( fd, p, len );
556 else// buffered file
557nwritten = fwrite( p, 1, len, fh );
558 if ( nwritten != (int)len ) {// write error
559if ( errno == ENOSPC )// disk is full
560 setStatus( IO_ResourceError );
561else
562 setStatus( IO_WriteError );
563if ( isRaw() )// recalc file position
564 ioIndex = (int)LSEEK( fd, 0, SEEK_CUR );
565else
566 ioIndex = fseek( fh, 0, SEEK_CUR );
567 } else {
568ioIndex += nwritten;
569 }
570 if ( ioIndex > length )// update file length
571length = 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
586int QFile::handle() const
587{
588 if ( !isOpen() )
589return -1;
590 else if ( fh )
591return FILENO( fh );
592 else
593return 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
613void QFile::close()
614{
615 bool ok = FALSE;
616 if ( isOpen() ) {// file is not open
617if ( fh ) {// buffered file
618 if ( ext_f )
619ok = fflush( fh ) != -1;// flush instead of closing
620 else
621ok = fclose( fh ) != -1;
622} else {// raw file
623 if ( ext_f )
624ok = TRUE;// cannot close
625 else
626ok = CLOSE( fd ) != -1;
627}
628init();// restore internal state
629 }
630 if (!ok)
631setStatus (IO_UnspecifiedError);
632
633 return;
634}
635
636int64 QFile::pos() const
637{
638 if (isOpen())
639 {
640 // TODO: support 64 bit size
641 return ftell( fh );
642 }
643 return -1;
644}
645
646int64 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
659bool 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
669

Archive Download this file

Revision: 1322