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