|
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 |