Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 1322