summaryrefslogtreecommitdiff
path: root/qmake/tools/qfile_unix.cpp
Unidiff
Diffstat (limited to 'qmake/tools/qfile_unix.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--qmake/tools/qfile_unix.cpp687
1 files changed, 687 insertions, 0 deletions
diff --git a/qmake/tools/qfile_unix.cpp b/qmake/tools/qfile_unix.cpp
new file mode 100644
index 0000000..2d5a856
--- a/dev/null
+++ b/qmake/tools/qfile_unix.cpp
@@ -0,0 +1,687 @@
1/****************************************************************************
2** $Id$
3**
4** Implementation of QFile class
5**
6** Created : 950628
7**
8** Copyright (C) 1992-2002 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 "qplatformdefs.h"
39
40// POSIX Large File Support redefines open -> open64
41static inline int qt_open(const char *pathname, int flags, mode_t mode)
42{ return ::open(pathname, flags, mode); }
43#if defined(open)
44# undef open
45#endif
46
47// POSIX Large File Support redefines truncate -> truncate64
48#if defined(truncate)
49# undef truncate
50#endif
51
52#include "qfile.h"
53#include <errno.h>
54#include <limits.h>
55
56
57bool qt_file_access( const QString& fn, int t )
58{
59 if ( fn.isEmpty() )
60 return FALSE;
61 return ::access( QFile::encodeName(fn), t ) == 0;
62}
63
64/*!
65 \overload
66 Removes the file \a fileName.
67 Returns TRUE if successful, otherwise FALSE.
68*/
69
70bool QFile::remove( const QString &fileName )
71{
72 if ( fileName.isEmpty() ) {
73#if defined(QT_CHECK_NULL)
74 qWarning( "QFile::remove: Empty or null file name" );
75#endif
76 return FALSE;
77 }
78 return unlink( QFile::encodeName(fileName) ) == 0;
79}
80
81#if defined(O_NONBLOCK)
82# define HAS_ASYNC_FILEMODE
83# define OPEN_ASYNC O_NONBLOCK
84#elif defined(O_NDELAY)
85# define HAS_ASYNC_FILEMODE
86# define OPEN_ASYNC O_NDELAY
87#endif
88
89/*!
90 Opens the file specified by the file name currently set, using the
91 mode \a m. Returns TRUE if successful, otherwise FALSE.
92
93 \keyword IO_Raw
94 \keyword IO_ReadOnly
95 \keyword IO_WriteOnly
96 \keyword IO_ReadWrite
97 \keyword IO_Append
98 \keyword IO_Truncate
99 \keyword IO_Translate
100
101 The mode parameter \a m must be a combination of the following flags:
102 \table
103 \header \i Flag \i Meaning
104 \row \i IO_Raw
105 \i Raw (non-buffered) file access.
106 \row \i IO_ReadOnly
107 \i Opens the file in read-only mode.
108 \row \i IO_WriteOnly
109 \i Opens the file in write-only mode. If this flag is used
110 with another flag, e.g. \c IO_ReadOnly or \c IO_Raw or \c
111 IO_Append, the file is \e not truncated; but if used on
112 its own (or with \c IO_Truncate), the file is truncated.
113 \row \i IO_ReadWrite
114 \i Opens the file in read/write mode, equivalent to \c
115 (IO_ReadOnly | IO_WriteOnly).
116 \row \i IO_Append
117 \i Opens the file in append mode. (You must actually use \c
118 (IO_WriteOnly | IO_Append) to make the file writable and
119 to go into append mode.) This mode is very useful when you
120 want to write something to a log file. The file index is
121 set to the end of the file. Note that the result is
122 undefined if you position the file index manually using
123 at() in append mode.
124 \row \i IO_Truncate
125 \i Truncates the file.
126 \row \i IO_Translate
127 \i Enables carriage returns and linefeed translation for text
128 files under Windows.
129 \endtable
130
131 The raw access mode is best when I/O is block-operated using a 4KB
132 block size or greater. Buffered access works better when reading
133 small portions of data at a time.
134
135 \warning When working with buffered files, data may not be written
136 to the file at once. Call flush() to make sure that the data is
137 really written.
138
139 \warning If you have a buffered file opened for both reading and
140 writing you must not perform an input operation immediately after
141 an output operation or vice versa. You should always call flush()
142 or a file positioning operation, e.g. at(), between input and
143 output operations, otherwise the buffer may contain garbage.
144
145 If the file does not exist and \c IO_WriteOnly or \c IO_ReadWrite
146 is specified, it is created.
147
148 Example:
149 \code
150 QFile f1( "/tmp/data.bin" );
151 f1.open( IO_Raw | IO_ReadWrite );
152
153 QFile f2( "readme.txt" );
154 f2.open( IO_ReadOnly | IO_Translate );
155
156 QFile f3( "audit.log" );
157 f3.open( IO_WriteOnly | IO_Append );
158 \endcode
159
160 \sa name(), close(), isOpen(), flush()
161*/
162
163bool QFile::open( int m )
164{
165 if ( isOpen() ) { // file already open
166#if defined(QT_CHECK_STATE)
167 qWarning( "QFile::open: File already open" );
168#endif
169 return FALSE;
170 }
171 if ( fn.isNull() ) { // no file name defined
172#if defined(QT_CHECK_NULL)
173 qWarning( "QFile::open: No file name specified" );
174#endif
175 return FALSE;
176 }
177 init(); // reset params
178 setMode( m );
179 if ( !(isReadable() || isWritable()) ) {
180#if defined(QT_CHECK_RANGE)
181 qWarning( "QFile::open: File access not specified" );
182#endif
183 return FALSE;
184 }
185 bool ok = TRUE;
186 struct stat st;
187 if ( isRaw() ) {
188 int oflags = O_RDONLY;
189 if ( isReadable() && isWritable() )
190 oflags = O_RDWR;
191 else if ( isWritable() )
192 oflags = O_WRONLY;
193 if ( flags() & IO_Append ) { // append to end of file?
194 if ( flags() & IO_Truncate )
195 oflags |= (O_CREAT | O_TRUNC);
196 else
197 oflags |= (O_APPEND | O_CREAT);
198 setFlags( flags() | IO_WriteOnly ); // append implies write
199 } else if ( isWritable() ) { // create/trunc if writable
200 if ( flags() & IO_Truncate )
201 oflags |= (O_CREAT | O_TRUNC);
202 else
203 oflags |= O_CREAT;
204 }
205#if defined(HAS_TEXT_FILEMODE)
206 if ( isTranslated() )
207 oflags |= OPEN_TEXT;
208 else
209 oflags |= OPEN_BINARY;
210#endif
211#if defined(HAS_ASYNC_FILEMODE)
212 if ( isAsynchronous() )
213 oflags |= OPEN_ASYNC;
214#endif
215 fd = qt_open( QFile::encodeName(fn), oflags, 0666 );
216
217 if ( fd != -1 ) { // open successful
218 ::fstat( fd, &st ); // get the stat for later usage
219 } else {
220 ok = FALSE;
221 }
222 } else { // buffered file I/O
223 QCString perm;
224 char perm2[4];
225 bool try_create = FALSE;
226 if ( flags() & IO_Append ) { // append to end of file?
227 setFlags( flags() | IO_WriteOnly ); // append implies write
228 perm = isReadable() ? "a+" : "a";
229 } else {
230 if ( isReadWrite() ) {
231 if ( flags() & IO_Truncate ) {
232 perm = "w+";
233 } else {
234 perm = "r+";
235 try_create = TRUE; // try to create if not exists
236 }
237 } else if ( isReadable() ) {
238 perm = "r";
239 } else if ( isWritable() ) {
240 perm = "w";
241 }
242 }
243 qstrcpy( perm2, perm );
244#if defined(HAS_TEXT_FILEMODE)
245 if ( isTranslated() )
246 strcat( perm2, "t" );
247 else
248 strcat( perm2, "b" );
249#endif
250 for (;;) { // At most twice
251
252 fh = fopen( QFile::encodeName(fn), perm2 );
253
254 if ( !fh && try_create ) {
255 perm2[0] = 'w'; // try "w+" instead of "r+"
256 try_create = FALSE;
257 } else {
258 break;
259 }
260 }
261 if ( fh ) {
262 ::fstat( fileno(fh), &st ); // get the stat for later usage
263 } else {
264 ok = FALSE;
265 }
266 }
267 if ( ok ) {
268 setState( IO_Open );
269 // on successful open the file stat was got; now test what type
270 // of file we have
271 if ( (st.st_mode & S_IFMT) != S_IFREG ) {
272 // non-seekable
273 setType( IO_Sequential );
274 length = INT_MAX;
275 ioIndex = 0;
276 } else {
277 length = (Offset)st.st_size;
278 ioIndex = (flags() & IO_Append) == 0 ? 0 : length;
279 if ( !(flags()&IO_Truncate) && length == 0 && isReadable() ) {
280 // try if you can read from it (if you can, it's a sequential
281 // device; e.g. a file in the /proc filesystem)
282 int c = getch();
283 if ( c != -1 ) {
284 ungetch(c);
285 setType( IO_Sequential );
286 length = INT_MAX;
287 ioIndex = 0;
288 }
289 }
290 }
291 } else {
292 init();
293 if ( errno == EMFILE ) // no more file handles/descrs
294 setStatus( IO_ResourceError );
295 else
296 setStatus( IO_OpenError );
297 }
298 return ok;
299}
300
301/*!
302 \overload
303 Opens a file in the mode \a m using an existing file handle \a f.
304 Returns TRUE if successful, otherwise FALSE.
305
306 Example:
307 \code
308 #include <stdio.h>
309
310 void printError( const char* msg )
311 {
312 QFile f;
313 f.open( IO_WriteOnly, stderr );
314 f.writeBlock( msg, qstrlen(msg) );// write to stderr
315 f.close();
316 }
317 \endcode
318
319 When a QFile is opened using this function, close() does not actually
320 close the file, only flushes it.
321
322 \warning If \a f is \c stdin, \c stdout, \c stderr, you may not
323 be able to seek. See QIODevice::isSequentialAccess() for more
324 information.
325
326 \sa close()
327*/
328
329bool QFile::open( int m, FILE *f )
330{
331 if ( isOpen() ) {
332#if defined(QT_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 fh = f;
341 ext_f = TRUE;
342 struct stat st;
343 ::fstat( fileno(fh), &st );
344#if defined(QT_LARGEFILE_SUPPORT)
345 ioIndex = (Offset)ftello( fh );
346#else
347 ioIndex = (Offset)ftell( fh );
348#endif
349 if ( (st.st_mode & S_IFMT) != S_IFREG || f == stdin ) { //stdin is non seekable
350 // non-seekable
351 setType( IO_Sequential );
352 length = INT_MAX;
353 ioIndex = 0;
354 } else {
355 length = (Offset)st.st_size;
356 if ( !(flags()&IO_Truncate) && length == 0 && isReadable() ) {
357 // try if you can read from it (if you can, it's a sequential
358 // device; e.g. a file in the /proc filesystem)
359 int c = getch();
360 if ( c != -1 ) {
361 ungetch(c);
362 setType( IO_Sequential );
363 length = INT_MAX;
364 ioIndex = 0;
365 }
366 }
367 }
368 return TRUE;
369}
370
371/*!
372 \overload
373 Opens a file in the mode \a m using an existing file descriptor \a f.
374 Returns TRUE if successful, otherwise FALSE.
375
376 When a QFile is opened using this function, close() does not actually
377 close the file.
378
379 The QFile that is opened using this function, is automatically set to be in
380 raw mode; this means that the file input/output functions are slow. If you
381 run into performance issues, you should try to use one of the other open
382 functions.
383
384 \warning If \a f is one of 0 (stdin), 1 (stdout) or 2 (stderr), you may not
385 be able to seek. size() is set to \c INT_MAX (in limits.h).
386
387 \sa close()
388*/
389
390
391bool QFile::open( int m, int f )
392{
393 if ( isOpen() ) {
394#if defined(QT_CHECK_RANGE)
395 qWarning( "QFile::open: File already open" );
396#endif
397 return FALSE;
398 }
399 init();
400 setMode( m |IO_Raw );
401 setState( IO_Open );
402 fd = f;
403 ext_f = TRUE;
404 struct stat st;
405 ::fstat( fd, &st );
406 ioIndex = (Offset)::lseek(fd, 0, SEEK_CUR);
407 if ( (st.st_mode & S_IFMT) != S_IFREG || f == 0 ) { // stdin is not seekable...
408 // non-seekable
409 setType( IO_Sequential );
410 length = INT_MAX;
411 ioIndex = 0;
412 } else {
413 length = (Offset)st.st_size;
414 if ( length == 0 && isReadable() ) {
415 // try if you can read from it (if you can, it's a sequential
416 // device; e.g. a file in the /proc filesystem)
417 int c = getch();
418 if ( c != -1 ) {
419 ungetch(c);
420 setType( IO_Sequential );
421 length = INT_MAX;
422 ioIndex = 0;
423 }
424 resetStatus();
425 }
426 }
427 return TRUE;
428}
429
430/*!
431 Returns the file size.
432 \sa at()
433*/
434
435QIODevice::Offset QFile::size() const
436{
437 struct stat st;
438 if ( isOpen() ) {
439 ::fstat( fh ? fileno(fh) : fd, &st );
440 } else {
441 ::stat( QFile::encodeName(fn), &st );
442 }
443#if defined(QT_LARGEFILE_SUPPORT) && !defined(QT_ABI_64BITOFFSET)
444 return (uint)st.st_size > UINT_MAX ? UINT_MAX : (QIODevice::Offset)st.st_size;
445#else
446 return st.st_size;
447#endif
448}
449
450
451/*!
452 \overload
453
454 Sets the file index to \a pos. Returns TRUE if successful;
455 otherwise returns FALSE.
456
457 Example:
458 \code
459 QFile f( "data.bin" );
460 f.open( IO_ReadOnly ); // index set to 0
461 f.at( 100 ); // set index to 100
462 f.at( f.at()+50 ); // set index to 150
463 f.at( f.size()-80 ); // set index to 80 before EOF
464 f.close();
465 \endcode
466
467 Use \c at() without arguments to retrieve the file offset.
468
469 \warning The result is undefined if the file was open()'ed using
470 the \c IO_Append specifier.
471
472 \sa size(), open()
473*/
474
475bool QFile::at( Offset pos )
476{
477 if ( !isOpen() ) {
478#if defined(QT_CHECK_STATE)
479 qWarning( "QFile::at: File is not open" );
480#endif
481 return FALSE;
482 }
483 if ( isSequentialAccess() )
484 return FALSE;
485 bool ok;
486 if ( isRaw() ) {
487 off_t l = ::lseek( fd, pos, SEEK_SET );
488 ok = ( l != -1 );
489 pos = (Offset)l;
490 } else { // buffered file
491#if defined(QT_LARGEFILE_SUPPORT)
492 ok = ( ::fseeko(fh, pos, SEEK_SET) == 0 );
493#else
494 ok = ( ::fseek(fh, pos, SEEK_SET) == 0 );
495#endif
496 }
497 if ( ok )
498 ioIndex = pos;
499#if defined(QT_CHECK_RANGE)
500 else
501#if defined(QT_LARGEFILE_SUPPORT) && defined(QT_ABI_64BITOFFSET)
502 qWarning( "QFile::at: Cannot set file position %llu", pos );
503#else
504 qWarning( "QFile::at: Cannot set file position %lu", pos );
505#endif
506#endif
507 return ok;
508}
509
510/*!
511 \reimp
512
513 \warning We have experienced problems with some C libraries when a buffered
514 file is opened for both reading and writing. If a read operation takes place
515 immediately after a write operation, the read buffer contains garbage data.
516 Worse, the same garbage is written to the file. Calling flush() before
517 readBlock() solved this problem.
518*/
519
520Q_LONG QFile::readBlock( char *p, Q_ULONG len )
521{
522#if defined(QT_CHECK_NULL)
523 if ( !p )
524 qWarning( "QFile::readBlock: Null pointer error" );
525#endif
526#if defined(QT_CHECK_STATE)
527 if ( !isOpen() ) {
528 qWarning( "QFile::readBlock: File not open" );
529 return -1;
530 }
531 if ( !isReadable() ) {
532 qWarning( "QFile::readBlock: Read operation not permitted" );
533 return -1;
534 }
535#endif
536 Q_ULONG nread = 0; // number of bytes read
537 if ( !ungetchBuffer.isEmpty() ) {
538 // need to add these to the returned string.
539 uint l = ungetchBuffer.length();
540 while( nread < l ) {
541 *p = ungetchBuffer[ l - nread - 1 ];
542 p++;
543 nread++;
544 }
545 ungetchBuffer.truncate( l - nread );
546 }
547
548 if ( nread < len ) {
549 if ( isRaw() ) { // raw file
550 nread += ::read( fd, p, len-nread );
551 if ( len && nread <= 0 ) {
552 nread = 0;
553 setStatus(IO_ReadError);
554 }
555 } else { // buffered file
556 nread += fread( p, 1, len-nread, fh );
557 if ( (uint)nread != len ) {
558 if ( ferror( fh ) || nread==0 )
559 setStatus(IO_ReadError);
560 }
561 }
562 }
563 if ( !isSequentialAccess() )
564 ioIndex += nread;
565 return nread;
566}
567
568
569/*! \reimp
570
571 Writes \a len bytes from \a p to the file and returns the number of
572 bytes actually written.
573
574 Returns -1 if a serious error occurred.
575
576 \warning When working with buffered files, data may not be written
577 to the file at once. Call flush() to make sure the data is really
578 written.
579
580 \sa readBlock()
581*/
582
583Q_LONG QFile::writeBlock( const char *p, Q_ULONG len )
584{
585#if defined(QT_CHECK_NULL)
586 if ( p == 0 && len != 0 )
587 qWarning( "QFile::writeBlock: Null pointer error" );
588#endif
589#if defined(QT_CHECK_STATE)
590 if ( !isOpen() ) { // file not open
591 qWarning( "QFile::writeBlock: File not open" );
592 return -1;
593 }
594 if ( !isWritable() ) { // writing not permitted
595 qWarning( "QFile::writeBlock: Write operation not permitted" );
596 return -1;
597 }
598#endif
599 Q_ULONG nwritten; // number of bytes written
600 if ( isRaw() ) // raw file
601 nwritten = ::write( fd, (void *)p, len );
602 else // buffered file
603 nwritten = fwrite( p, 1, len, fh );
604 if ( nwritten != len ) { // write error
605 if ( errno == ENOSPC ) // disk is full
606 setStatus( IO_ResourceError );
607 else
608 setStatus( IO_WriteError );
609 if ( !isSequentialAccess() ) {
610 if ( isRaw() ) // recalc file position
611 ioIndex = (Offset)::lseek( fd, 0, SEEK_CUR );
612 else
613#if defined(QT_LARGEFILE_SUPPORT)
614 ioIndex = (Offset)::fseeko( fh, 0, SEEK_CUR );
615#else
616 ioIndex = (Offset)::fseek( fh, 0, SEEK_CUR );
617#endif
618 }
619 } else {
620 if ( !isSequentialAccess() )
621 ioIndex += nwritten;
622 }
623 if ( ioIndex > length ) // update file length
624 length = ioIndex;
625 return nwritten;
626}
627
628/*!
629 Returns the file handle of the file.
630
631 This is a small positive integer, suitable for use with C library
632 functions such as fdopen() and fcntl(), as well as with QSocketNotifier.
633
634 If the file is not open or there is an error, handle() returns -1.
635
636 \sa QSocketNotifier
637*/
638
639int QFile::handle() const
640{
641 if ( !isOpen() )
642 return -1;
643 else if ( fh )
644 return fileno( fh );
645 else
646 return fd;
647}
648
649/*!
650 Closes an open file.
651
652 The file is not closed if it was opened with an existing file handle.
653 If the existing file handle is a \c FILE*, the file is flushed.
654 If the existing file handle is an \c int file descriptor, nothing
655 is done to the file.
656
657 Some "write-behind" filesystems may report an unspecified error on
658 closing the file. These errors only indicate that something may
659 have gone wrong since the previous open(). In such a case status()
660 reports IO_UnspecifiedError after close(), otherwise IO_Ok.
661
662 \sa open(), flush()
663*/
664
665
666void QFile::close()
667{
668 bool ok = FALSE;
669 if ( isOpen() ) { // file is not open
670 if ( fh ) { // buffered file
671 if ( ext_f )
672 ok = fflush( fh ) != -1;// flush instead of closing
673 else
674 ok = fclose( fh ) != -1;
675 } else { // raw file
676 if ( ext_f )
677 ok = TRUE; // cannot close
678 else
679 ok = ::close( fd ) != -1;
680 }
681 init(); // restore internal state
682 }
683 if (!ok)
684 setStatus( IO_UnspecifiedError );
685
686 return;
687}