1 /******************************************************************************
5 * Copyright (C) 1997-2001 by Dimitri van Heesch.
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.
13 * Documents produced by Doxygen are derivative works derived from the
14 * input used in their production; they are not affected by this license.
16 * Based on qdir_unix.cpp
18 * Copyright (C) 1992-2000 Trolltech AS.
28 #include "qfileinfo.h"
29 #include "qfiledefs_p.h"
31 #include "qstringlist.h"
34 #if defined(_OS_WIN32_)
35 #if defined(_CC_BOOL_DEF_)
43 #if defined(_OS_OS2EMX_)
44 extern Q_UINT32 DosQueryCurrentDisk(Q_UINT32*,Q_UINT32*);
48 extern QStringList qt_makeFilterList( const QString &filter );
50 extern int qt_cmp_si_sortSpec;
52 #if defined(Q_C_CALLBACKS)
56 extern int qt_cmp_si( const void *, const void * );
58 #if defined(Q_C_CALLBACKS)
62 static QString p_getenv( QString name )
64 DWORD len = GetEnvironmentVariableW( ( LPCWSTR ) qt_winTchar ( name, TRUE ), NULL, 0 );
67 /* ansi: we allocate too much memory, but this shouldn't be the problem here ... */
68 LPWSTR buf = (LPWSTR)new WCHAR[ len ];
69 len = GetEnvironmentVariableW ( ( LPCWSTR ) qt_winTchar ( name, TRUE ), buf, len );
75 QString ret = qt_winQString ( buf );
81 void QDir::slashify( QString& n )
83 for ( int i=0; i<(int)n.length(); i++ )
90 QString QDir::homeDirPath()
92 QString d = p_getenv ( "HOME" );
94 d = p_getenv ( "USERPROFILE" );
96 QString homeDrive = p_getenv ( "HOMEDRIVE" );
97 QString homePath = p_getenv ( "HOMEPATH" );
98 if ( !homeDrive.isNull () && !homePath.isNull () ) {
99 d = homeDrive + homePath;
109 QString QDir::canonicalPath() const
115 GETCWD( cur, PATH_MAX );
116 if ( CHDIR(QFile::encodeName(dPath)) >= 0 ) {
117 GETCWD( tmp, PATH_MAX );
118 r = QFile::decodeName(tmp);
126 bool QDir::mkdir( const QString &dirName, bool acceptAbsPath ) const
128 #if defined(__CYGWIN32_)
129 return MKDIR( QFile::encodeName(filePath(dirName,acceptAbsPath)), 0777 ) == 0;
131 return _wmkdir( ( LPCWSTR ) filePath( dirName, acceptAbsPath ).ucs2() ) == 0;
135 bool QDir::rmdir( const QString &dirName, bool acceptAbsPath ) const
137 #if defined(__CYGWIN32_)
138 return RMDIR( QFile::encodeName(filePath(dirName,acceptAbsPath)) ) == 0;
140 return _wrmdir( ( LPCWSTR ) filePath( dirName, acceptAbsPath ).ucs2() ) == 0;
144 bool QDir::isReadable() const
146 QString path = dPath;
147 if ( ( path[ 0 ] == '\\' ) || ( path[ 0 ] == '/' ) )
148 path = rootDirPath() + path;
149 #if defined(__CYGWIN32_)
150 return ACCESS( QFile::encodeName(dPath), R_OK ) == 0;
152 return ( _waccess( (wchar_t*) path.ucs2(), R_OK ) == 0 );
156 bool QDir::isRoot() const
158 QString path = dPath;
160 return path == rootDirPath ();
163 bool QDir::rename( const QString &name, const QString &newName,
164 bool acceptAbsPaths )
166 if ( name.isEmpty() || newName.isEmpty() ) {
167 #if defined(CHECK_NULL)
168 qWarning( "QDir::rename: Empty or null file name(s)" );
172 QString fn1 = filePath( name, acceptAbsPaths );
173 QString fn2 = filePath( newName, acceptAbsPaths );
174 #if defined(__CYGWIN32_)
175 return ::rename( QFile::encodeName(fn1),
176 QFile::encodeName(fn2) ) == 0;
178 return MoveFileW( ( LPCWSTR ) fn1.ucs2(), ( LPCWSTR ) fn2.ucs2() ) != 0;
182 bool QDir::setCurrent( const QString &path )
184 #if defined(__CYGWIN32_)
186 r = CHDIR( QFile::encodeName(path) );
189 if ( !QDir( path ).exists() )
191 return ( SetCurrentDirectoryW( ( LPCWSTR ) path.ucs2() ) >= 0 );
195 QString QDir::currentDirPath()
199 #if defined(__CYGWIN32_)
202 if ( STAT( ".", &st ) == 0 ) {
203 char currentName[PATH_MAX];
204 if ( GETCWD( currentName, PATH_MAX ) != 0 )
205 result = QFile::decodeName(currentName);
207 if ( result.isNull() )
208 qWarning( "QDir::currentDirPath: getcwd() failed" );
212 qWarning( "QDir::currentDirPath: stat(\".\") failed" );
219 WCHAR currentName[ PATH_MAX ];
220 size = ::GetCurrentDirectoryW( PATH_MAX, currentName );
222 if ( size > PATH_MAX ) {
223 WCHAR * newCurrentName = new WCHAR[ size ];
224 if ( ::GetCurrentDirectoryW( PATH_MAX, newCurrentName ) != 0 )
225 result = QString::fromUcs2( ( ushort* ) newCurrentName );
226 delete [] newCurrentName;
228 result = QString::fromUcs2( ( ushort* ) currentName );
232 if ( result.length() >= 2 && result[ 1 ] == ':' )
233 result[ 0 ] = result.at( 0 ).upper(); // Force uppercase drive letters.
239 QString QDir::rootDirPath()
241 QString d = p_getenv ( "SystemDrive" );
243 d = QString::fromLatin1( "c:" ); // not "c:\\" !
248 bool QDir::isRelativePath( const QString &path )
250 if ( path.isEmpty() )
253 if ( path[ 0 ].isLetter() && path[ 1 ] == ':' )
254 p = 2; // we have checked the first 2.
255 return ( ( path[ p ] != '/' ) && ( path[ p ] != '\\' ) );
267 #if defined(_OS_WIN32_)
268 #define IS_SUBDIR FILE_ATTRIBUTE_DIRECTORY
269 #define IS_RDONLY FILE_ATTRIBUTE_READONLY
270 #define IS_ARCH FILE_ATTRIBUTE_ARCHIVE
271 #define IS_HIDDEN FILE_ATTRIBUTE_HIDDEN
272 #define IS_SYSTEM FILE_ATTRIBUTE_SYSTEM
273 #define FF_GETFIRST FindFirstFile
274 #define FF_GETNEXT FindNextFile
275 #define FF_ERROR INVALID_HANDLE_VALUE
277 #define IS_SUBDIR _A_SUBDIR
278 #define IS_RDONLY _A_RDONLY
279 #define IS_ARCH _A_ARCH
280 #define IS_HIDDEN _A_HIDDEN
281 #define IS_SYSTEM _A_SYSTEM
282 #define FF_GETFIRST _findfirst
283 #define FF_GETNEXT _findnext
288 bool QDir::readDirEntries( const QString &nameFilter,
289 int filterSpec, int sortSpec )
293 fList = new QStringList;
295 fiList = new QFileInfoList;
297 fiList->setAutoDelete( TRUE );
303 QStringList filters = qt_makeFilterList( nameFilter );
305 bool doDirs = (filterSpec & Dirs) != 0;
306 bool doFiles = (filterSpec & Files) != 0;
307 bool noSymLinks = (filterSpec & NoSymLinks) != 0;
308 bool doReadable = (filterSpec & Readable) != 0;
309 bool doWritable = (filterSpec & Writable) != 0;
310 bool doExecable = (filterSpec & Executable) != 0;
311 bool doHidden = (filterSpec & Hidden) != 0;
312 // show hidden files if the user asks explicitly for e.g. .*
313 if ( !doHidden && !nameFilter.isEmpty() && nameFilter[0] == '.' )
315 bool doModified = (filterSpec & Modified) != 0;
316 bool doSystem = (filterSpec & System) != 0;
318 QRegExp wc( nameFilter.data(), FALSE, TRUE ); // wild card, case insensitive
320 QString p = dPath.copy();
321 int plen = p.length();
322 #if defined(_OS_WIN32_)
324 WIN32_FIND_DATAW finfo;
332 #if defined(CHECK_NULL)
333 warning( "QDir::readDirEntries: No directory name specified" );
337 if ( p.at(plen-1) != '/' && p.at(plen-1) != '\\' )
341 #if defined(__CYGWIN32_)
342 ff = FF_GETFIRST( p.data(), &finfo );
344 ff = FindFirstFileW ( ( LPCWSTR ) p.ucs2(), &finfo );
346 if ( ff == FF_ERROR )
349 warning( "QDir::readDirEntries: Cannot read the directory: %s",
350 (const char *)dPath.utf8() );
361 #if defined(__CYGWIN32_)
362 if ( FF_GETNEXT(ff,&finfo) == -1 )
365 //if ( !FF_GETNEXT(ff,&finfo) )
367 if (!FindNextFileW(ff, &finfo ))
371 #if defined(__CYGWIN32_)
372 int attrib = finfo.attrib;
374 int attrib = finfo.dwFileAttributes;
376 bool isDir = (attrib & IS_SUBDIR) != 0;
377 bool isFile = !isDir;
378 bool isSymLink = FALSE;
379 bool isReadable = TRUE;
380 bool isWritable = (attrib & IS_RDONLY) == 0;
381 bool isExecable = FALSE;
382 bool isModified = (attrib & IS_ARCH) != 0;
383 bool isHidden = (attrib & IS_HIDDEN) != 0;
384 bool isSystem = (attrib & IS_SYSTEM) != 0;
386 #if defined(__CYGWIN32_)
387 const char *fname = finfo.name;
389 //const char *fname = finfo.cFileName;
390 QString fname = QString::fromUcs2( ( const unsigned short* ) finfo.cFileName);
392 if ( wc.match(fname.utf8()) == -1 && !(allDirs && isDir) )
395 QString name = fname;
398 QString ext = name.right(4).lower();
399 if ( ext == ".exe" || ext == ".com" || ext == ".bat" ||
400 ext == ".pif" || ext == ".cmd" )
404 if ( (doDirs && isDir) || (doFiles && isFile) )
406 if ( noSymLinks && isSymLink )
408 if ( (filterSpec & RWEMask) != 0 )
409 if ( (doReadable && !isReadable) ||
410 (doWritable && !isWritable) ||
411 (doExecable && !isExecable) )
413 if ( doModified && !isModified )
415 if ( !doHidden && isHidden )
417 if ( !doSystem && isSystem )
419 fi.setFile( *this, name );
420 fiList->append( new QFileInfo( fi ) );
423 #if defined(__CYGWIN32_)
430 QDirSortItem* si= new QDirSortItem[fiList->count()];
433 for (itm = fiList->first(); itm; itm = fiList->next())
435 qt_cmp_si_sortSpec = sortSpec;
436 qsort( si, i, sizeof(si[0]), qt_cmp_si );
437 // put them back in the list
438 fiList->setAutoDelete( FALSE );
441 for ( j=0; j<i; j++ ) {
442 fiList->append( si[j].item );
443 fList->append( si[j].item->fileName() );
446 fiList->setAutoDelete( TRUE );
448 if ( filterSpec == (FilterSpec)filtS && sortSpec == (SortSpec)sortS &&
449 nameFilter == nameFilt )
456 const QFileInfoList * QDir::drives()
458 // at most one instance of QFileInfoList is leaked, and this variable
459 // points to that list
460 static QFileInfoList * knownMemoryLeak = 0;
462 if ( !knownMemoryLeak ) {
463 knownMemoryLeak = new QFileInfoList;
465 #if defined(_OS_WIN32_)
466 Q_UINT32 driveBits = (Q_UINT32) GetLogicalDrives() & 0x3ffffff;
467 #elif defined(_OS_OS2EMX_)
468 Q_UINT32 driveBits, cur;
469 if (DosQueryCurrentDisk(&cur,&driveBits) != NO_ERROR)
471 driveBits &= 0x3ffffff;
474 qstrcpy( driveName, "a:/" );
477 knownMemoryLeak->append( new QFileInfo( driveName ) );
479 driveBits = driveBits >> 1;
483 return knownMemoryLeak;