source: trunk/src/tools/qfile_pm.cpp@ 127

Last change on this file since 127 was 127, checked in by dmik, 19 years ago

Tools: Fixed file name validation: QFile::open() didn't work for file names containing non-Latin1 characters (thanks to froloff for reporting).

  • Property svn:keywords set to Id
File size: 11.4 KB
Line 
1/****************************************************************************
2** $Id: qfile_pm.cpp 127 2006-09-14 20:19:10Z dmik $
3**
4** Implementation of QFileInfo class
5**
6** Copyright (C) 1992-2002 Trolltech AS. All rights reserved.
7** Copyright (C) 2004 Norman ASA. Initial OS/2 Port.
8** Copyright (C) 2005 netlabs.org. Further OS/2 Development.
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 may use this file in accordance with the Qt Commercial License
23** 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#include "qfile.h"
41#include "qfiledefs_p.h"
42#include <limits.h>
43
44extern const char* qt_fileerr_read;
45
46bool qt_file_access( const QString& fn, int t )
47{
48 if ( fn.isEmpty() )
49 return FALSE;
50 return QT_ACCESS( QFile::encodeName( fn ), t) == 0;
51}
52
53bool isValidFile( const QString& fileName )
54{
55 // Since fopen() in many compilers simply returns ENOENT when an
56 // illegal character is used in the filename we do some validation
57 // here to produce a more informative message in QFile::open().
58 // NOTE: only HPFS limitations (which are less restrictive than FAT)
59 // are applied.
60 static const char *badChars = "|<>\"?*";
61 for ( int i = 0; i < (int) fileName.length(); i++) {
62 if ( fileName[i] < QChar( 32 ) )
63 return FALSE;
64 int ch = fileName[i].latin1();
65 if ( !ch )
66 continue;
67 if ( strchr( badChars, ch ) )
68 return FALSE;
69 }
70 int findColon = fileName.findRev( ':' );
71 if ( findColon == -1 )
72 return TRUE;
73 else if ( findColon != 1 )
74 return FALSE;
75 else
76 return fileName[0].isLetter();
77}
78
79bool QFile::remove( const QString &fileName )
80{
81 if ( fileName.isEmpty() ) {
82#if defined(QT_CHECK_NULL)
83 qWarning( "QFile::remove: Empty or null file name" );
84#endif
85 return FALSE;
86 }
87 return ::remove( QFile::encodeName( fileName ) ) == 0;
88}
89
90#define HAS_TEXT_FILEMODE
91
92bool QFile::open( int m )
93{
94 if ( isOpen() ) { // file already open
95#if defined(QT_CHECK_STATE)
96 qWarning( "QFile::open: File already open" );
97#endif
98 return FALSE;
99 }
100 if ( fn.isEmpty() ) { // no file name defined
101#if defined(QT_CHECK_NULL)
102 qWarning( "QFile::open: No file name specified" );
103#endif
104 return FALSE;
105 }
106 init(); // reset params
107 setMode( m );
108 if ( !(isReadable() || isWritable()) ) {
109#if defined(QT_CHECK_RANGE)
110 qWarning( "QFile::open: File access not specified" );
111#endif
112 return FALSE;
113 }
114 if ( !isValidFile( fn ) ) {
115 qWarning( "QFile::open: Invalid filename specified" );
116 return FALSE;
117 }
118
119 bool ok = TRUE;
120 if ( isRaw() ) { // raw file I/O
121 int oflags = QT_OPEN_RDONLY;
122 if ( isReadable() && isWritable() )
123 oflags = QT_OPEN_RDWR;
124 else if ( isWritable() )
125 oflags = QT_OPEN_WRONLY;
126 if ( flags() & IO_Append ) { // append to end of file?
127 if ( flags() & IO_Truncate )
128 oflags |= (QT_OPEN_CREAT | QT_OPEN_TRUNC);
129 else
130 oflags |= (QT_OPEN_APPEND | QT_OPEN_CREAT);
131 setFlags( flags() | IO_WriteOnly ); // append implies write
132 } else if ( isWritable() ) { // create/trunc if writable
133 if ( flags() & IO_Truncate )
134 oflags |= (QT_OPEN_CREAT | QT_OPEN_TRUNC);
135 else
136 oflags |= QT_OPEN_CREAT;
137 }
138#if defined(HAS_TEXT_FILEMODE)
139 if ( isTranslated() )
140 oflags |= QT_OPEN_TEXT;
141 else
142 oflags |= QT_OPEN_BINARY;
143#endif
144#if defined(HAS_ASYNC_FILEMODE)
145 if ( isAsynchronous() )
146 oflags |= QT_OPEN_ASYNC;
147#endif
148 fd = QT_OPEN( QFile::encodeName( fn ), oflags, 0666 );
149
150 if ( fd != -1 ) { // open successful
151 QT_STATBUF st;
152 QT_FSTAT( fd, &st );
153 if ( (st.st_mode& QT_STAT_MASK) == QT_STAT_DIR ) {
154 ok = FALSE;
155 } else {
156 length = (int)st.st_size;
157 ioIndex = (flags() & IO_Append) == 0 ? 0 : length;
158 }
159 } else {
160 ok = FALSE;
161 }
162 } else { // buffered file I/O
163 QCString perm;
164 char perm2[4];
165 bool try_create = FALSE;
166 if ( flags() & IO_Append ) { // append to end of file?
167 setFlags( flags() | IO_WriteOnly ); // append implies write
168 perm = isReadable() ? "a+" : "a";
169 } else {
170 if ( isReadWrite() ) {
171 if ( flags() & IO_Truncate ) {
172 perm = "w+";
173 } else {
174 perm = "r+";
175 try_create = TRUE; // try to create if not exists
176 }
177 } else if ( isReadable() ) {
178 perm = "r";
179 } else if ( isWritable() ) {
180 perm = "w";
181 }
182 }
183 qstrcpy( perm2, perm );
184#if defined(HAS_TEXT_FILEMODE)
185 if ( isTranslated() )
186 strcat( perm2, "t" );
187 else
188 strcat( perm2, "b" );
189#endif
190 for (;;) { // At most twice
191 fh = fopen( QFile::encodeName( fn ), perm2 );
192 if ( errno == EACCES )
193 break;
194 if ( !fh && try_create ) {
195 perm2[0] = 'w'; // try "w+" instead of "r+"
196 try_create = FALSE;
197 } else {
198 break;
199 }
200 }
201 if ( fh ) {
202 QT_STATBUF st;
203 QT_FSTAT( QT_FILENO(fh), &st );
204 if ( (st.st_mode& QT_STAT_MASK) == QT_STAT_DIR ) {
205 ok = FALSE;
206 } else {
207 length = (int)st.st_size;
208 ioIndex = (flags() & IO_Append) == 0 ? 0 : length;
209 }
210 } else {
211 ok = FALSE;
212 }
213 }
214 if ( ok ) {
215 setState( IO_Open );
216 } else {
217 init();
218 if ( errno == EMFILE ) // no more file handles/descrs
219 setStatus( IO_ResourceError );
220 else
221 setStatus( IO_OpenError );
222 setErrorStringErrno( errno );
223 }
224 return ok;
225}
226
227
228
229bool QFile::open( int m, FILE *f )
230{
231 if ( isOpen() ) {
232#if defined(QT_CHECK_RANGE)
233 qWarning( "QFile::open: File already open" );
234#endif
235 return FALSE;
236 }
237 init();
238 setMode( m &~IO_Raw );
239 setState( IO_Open );
240 fh = f;
241 ext_f = TRUE;
242 QT_STATBUF st;
243 QT_FSTAT( QT_FILENO(fh), &st );
244 ioIndex = (int)ftell( fh );
245 if ( (st.st_mode & QT_STAT_MASK) != QT_STAT_REG ) {
246 // non-seekable
247 setType( IO_Sequential );
248 length = INT_MAX;
249 } else {
250 length = (int)st.st_size;
251 }
252 return TRUE;
253}
254
255
256bool QFile::open( int m, int f )
257{
258 if ( isOpen() ) {
259#if defined(QT_CHECK_RANGE)
260 qWarning( "QFile::open: File already open" );
261#endif
262 return FALSE;
263 }
264 init();
265 setMode( m |IO_Raw );
266 setState( IO_Open );
267 fd = f;
268 ext_f = TRUE;
269 QT_STATBUF st;
270 QT_FSTAT( fd, &st );
271 ioIndex = (int)QT_LSEEK(fd, 0, SEEK_CUR);
272 if ( (st.st_mode & QT_STAT_MASK) != QT_STAT_REG ) {
273 // non-seekable
274 setType( IO_Sequential );
275 length = INT_MAX;
276 } else {
277 length = (int)st.st_size;
278 }
279 return TRUE;
280}
281
282QIODevice::Offset QFile::size() const
283{
284 QT_STATBUF st;
285 int ret = 0;
286 if ( isOpen() ) {
287 ret = QT_FSTAT( fh ? QT_FILENO(fh) : fd, &st );
288 } else {
289 ret = QT_STAT( QFile::encodeName( fn ), &st);
290 }
291 if ( ret == -1 )
292 return 0;
293 return st.st_size;
294}
295
296bool QFile::at( Offset pos )
297{
298 if ( !isOpen() ) {
299#if defined(QT_CHECK_STATE)
300 qWarning( "QFile::at: File is not open" );
301#endif
302 return FALSE;
303 }
304 bool okay;
305 if ( isRaw() ) { // raw file
306 pos = (int)QT_LSEEK(fd, pos, SEEK_SET);
307 okay = pos != (Q_ULONG)-1;
308 } else { // buffered file
309 okay = fseek(fh, pos, SEEK_SET) == 0;
310 }
311 if ( okay )
312 ioIndex = pos;
313#if defined(QT_CHECK_RANGE)
314 else
315 qWarning( "QFile::at: Cannot set file position %lu", pos );
316#endif
317 return okay;
318}
319
320Q_LONG QFile::readBlock( char *p, Q_ULONG len )
321{
322 if ( !len ) // nothing to do
323 return 0;
324
325#if defined(QT_CHECK_NULL)
326 if ( !p )
327 qWarning( "QFile::readBlock: Null pointer error" );
328#endif
329#if defined(QT_CHECK_STATE)
330 if ( !isOpen() ) { // file not open
331 qWarning( "QFile::readBlock: File not open" );
332 return -1;
333 }
334 if ( !isReadable() ) { // reading not permitted
335 qWarning( "QFile::readBlock: Read operation not permitted" );
336 return -1;
337 }
338#endif
339 Q_ULONG nread = 0; // number of bytes read
340 if ( !ungetchBuffer.isEmpty() ) {
341 // need to add these to the returned string.
342 Q_ULONG l = ungetchBuffer.length();
343 while( nread < l ) {
344 *p = ungetchBuffer[ int(l - nread - 1) ];
345 p++;
346 nread++;
347 }
348 ungetchBuffer.truncate( l - nread );
349 }
350
351 if( nread < len ) {
352 if ( isRaw() ) { // raw file
353 nread += QT_READ( fd, p, len - nread );
354 if ( len && nread <= 0 ) {
355 nread = 0;
356 setStatus(IO_ReadError);
357 setErrorStringErrno( errno );
358 }
359 } else { // buffered file
360 nread += fread( p, 1, len - nread, fh );
361 if ( (uint)nread != len ) {
362 if ( ferror( fh ) || nread==0 ) {
363 setStatus(IO_ReadError);
364 setErrorString( qt_fileerr_read );
365 }
366 }
367 }
368 }
369 ioIndex += nread;
370 return nread;
371}
372
373Q_LONG QFile::writeBlock( const char *p, Q_ULONG len )
374{
375 if ( !len ) // nothing to do
376 return 0;
377
378#if defined(QT_CHECK_NULL)
379 if ( p == 0 && len != 0 )
380 qWarning( "QFile::writeBlock: Null pointer error" );
381#endif
382#if defined(QT_CHECK_STATE)
383 if ( !isOpen() ) { // file not open
384 qWarning( "QFile::writeBlock: File not open" );
385 return -1;
386 }
387 if ( !isWritable() ) { // writing not permitted
388 qWarning( "QFile::writeBlock: Write operation not permitted" );
389 return -1;
390 }
391#endif
392 Q_ULONG nwritten; // number of bytes written
393 if ( isRaw() ) // raw file
394 nwritten = QT_WRITE( fd, p, len );
395 else // buffered file
396 nwritten = fwrite( p, 1, len, fh );
397 if ( nwritten != len ) { // write error
398 if ( errno == ENOSPC ) // disk is full
399 setStatus( IO_ResourceError );
400 else
401 setStatus( IO_WriteError );
402 setErrorStringErrno( errno );
403 if ( isRaw() ) // recalc file position
404 ioIndex = (int)QT_LSEEK( fd, 0, SEEK_CUR );
405 else
406 ioIndex = fseek( fh, 0, SEEK_CUR );
407 } else {
408 ioIndex += nwritten;
409 }
410 if ( ioIndex > length ) // update file length
411 length = ioIndex;
412 return nwritten;
413}
414
415int QFile::handle() const
416{
417 if ( !isOpen() )
418 return -1;
419 else if ( fh )
420 return QT_FILENO( fh );
421 else
422 return fd;
423}
424
425void QFile::close()
426{
427 bool ok = FALSE;
428 if ( isOpen() ) { // file is not open
429 if ( fh ) { // buffered file
430 if ( ext_f )
431 ok = fflush( fh ) != -1; // flush instead of closing
432 else
433 ok = fclose( fh ) != -1;
434 } else { // raw file
435 if ( ext_f )
436 ok = TRUE; // cannot close
437 else
438 ok = QT_CLOSE( fd ) != -1;
439 }
440 init(); // restore internal state
441 }
442 if (!ok) {
443 setStatus (IO_UnspecifiedError);
444 setErrorStringErrno( errno );
445 }
446
447 return;
448}
Note: See TracBrowser for help on using the repository browser.