tools/configure/environment.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the tools applications of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "environment.h"
       
    43 
       
    44 #include <process.h>
       
    45 #include <iostream>
       
    46 #include <qdebug.h>
       
    47 #include <QDir>
       
    48 #include <QStringList>
       
    49 #include <QMap>
       
    50 #include <QDir>
       
    51 #include <QFile>
       
    52 #include <QFileInfo>
       
    53 
       
    54 //#define CONFIGURE_DEBUG_EXECUTE
       
    55 //#define CONFIGURE_DEBUG_CP_DIR
       
    56 
       
    57 using namespace std;
       
    58 
       
    59 #ifdef Q_OS_WIN32
       
    60 #include <qt_windows.h>
       
    61 #endif
       
    62 
       
    63 
       
    64 QT_BEGIN_NAMESPACE
       
    65 
       
    66 struct CompilerInfo{
       
    67     Compiler compiler;
       
    68     const char *compilerStr;
       
    69     const char *regKey;
       
    70     const char *executable;
       
    71 } compiler_info[] = {
       
    72     // The compilers here are sorted in a reversed-preferred order
       
    73     {CC_BORLAND, "Borland C++",                                                    0, "bcc32.exe"},
       
    74     {CC_MINGW,   "MinGW (Minimalist GNU for Windows)",                             0, "mingw32-gcc.exe"},
       
    75     {CC_INTEL,   "Intel(R) C++ Compiler for 32-bit applications",                  0, "icl.exe"}, // xilink.exe, xilink5.exe, xilink6.exe, xilib.exe
       
    76     {CC_MSVC6,   "Microsoft (R) 32-bit C/C++ Optimizing Compiler (6.x)",           "Software\\Microsoft\\VisualStudio\\6.0\\Setup\\Microsoft Visual C++\\ProductDir", "cl.exe"}, // link.exe, lib.exe
       
    77     {CC_NET2002, "Microsoft (R) 32-bit C/C++ Optimizing Compiler.NET 2002 (7.0)",  "Software\\Microsoft\\VisualStudio\\7.0\\Setup\\VC\\ProductDir", "cl.exe"}, // link.exe, lib.exe
       
    78     {CC_NET2003, "Microsoft (R) 32-bit C/C++ Optimizing Compiler.NET 2003 (7.1)",  "Software\\Microsoft\\VisualStudio\\7.1\\Setup\\VC\\ProductDir", "cl.exe"}, // link.exe, lib.exe
       
    79     {CC_NET2005, "Microsoft (R) 32-bit C/C++ Optimizing Compiler.NET 2005 (8.0)",  "Software\\Microsoft\\VisualStudio\\SxS\\VC7\\8.0", "cl.exe"}, // link.exe, lib.exe
       
    80     {CC_NET2008, "Microsoft (R) 32-bit C/C++ Optimizing Compiler.NET 2008 (9.0)",  "Software\\Microsoft\\VisualStudio\\SxS\\VC7\\9.0", "cl.exe"}, // link.exe, lib.exe
       
    81     {CC_UNKNOWN, "Unknown", 0, 0},
       
    82 };
       
    83 
       
    84 
       
    85 // Initialize static variables
       
    86 Compiler Environment::detectedCompiler = CC_UNKNOWN;
       
    87 
       
    88 /*!
       
    89     Returns the pointer to the CompilerInfo for a \a compiler.
       
    90 */
       
    91 CompilerInfo *Environment::compilerInfo(Compiler compiler)
       
    92 {
       
    93     int i = 0;
       
    94     while(compiler_info[i].compiler != compiler && compiler_info[i].compiler != CC_UNKNOWN)
       
    95         ++i;
       
    96     return &(compiler_info[i]);
       
    97 }
       
    98 
       
    99 /*!
       
   100     Returns the path part of a registry key.
       
   101     Ei.
       
   102         For a key
       
   103             "Software\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\ProductDir"
       
   104         it returns
       
   105             "Software\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\"
       
   106 */
       
   107 QString Environment::keyPath(const QString &rKey)
       
   108 {
       
   109     int idx = rKey.lastIndexOf(QLatin1Char('\\'));
       
   110     if (idx == -1)
       
   111         return QString();
       
   112     return rKey.left(idx + 1);
       
   113 }
       
   114 
       
   115 /*!
       
   116     Returns the name part of a registry key.
       
   117     Ei.
       
   118         For a key
       
   119             "Software\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\ProductDir"
       
   120         it returns
       
   121             "ProductDir"
       
   122 */
       
   123 QString Environment::keyName(const QString &rKey)
       
   124 {
       
   125     int idx = rKey.lastIndexOf(QLatin1Char('\\'));
       
   126     if (idx == -1)
       
   127         return rKey;
       
   128 
       
   129     QString res(rKey.mid(idx + 1));
       
   130     if (res == "Default" || res == ".")
       
   131         res = "";
       
   132     return res;
       
   133 }
       
   134 
       
   135 /*!
       
   136     Returns a registry keys value in string form.
       
   137     If the registry key does not exist, or cannot be accessed, a
       
   138     QString() is returned.
       
   139 */
       
   140 QString Environment::readRegistryKey(HKEY parentHandle, const QString &rSubkey)
       
   141 {
       
   142 #ifndef Q_OS_WIN32
       
   143     return QString();
       
   144 #else
       
   145     QString rSubkeyName = keyName(rSubkey);
       
   146     QString rSubkeyPath = keyPath(rSubkey);
       
   147 
       
   148     HKEY handle = 0;
       
   149     LONG res = RegOpenKeyEx(parentHandle, (wchar_t*)rSubkeyPath.utf16(), 0, KEY_READ, &handle);
       
   150     if (res != ERROR_SUCCESS)
       
   151         return QString();
       
   152 
       
   153     // get the size and type of the value
       
   154     DWORD dataType;
       
   155     DWORD dataSize;
       
   156     res = RegQueryValueEx(handle, (wchar_t*)rSubkeyName.utf16(), 0, &dataType, 0, &dataSize);
       
   157     if (res != ERROR_SUCCESS) {
       
   158         RegCloseKey(handle);
       
   159         return QString();
       
   160     }
       
   161 
       
   162     // get the value
       
   163     QByteArray data(dataSize, 0);
       
   164     res = RegQueryValueEx(handle, (wchar_t*)rSubkeyName.utf16(), 0, 0,
       
   165                            reinterpret_cast<unsigned char*>(data.data()), &dataSize);
       
   166     if (res != ERROR_SUCCESS) {
       
   167         RegCloseKey(handle);
       
   168         return QString();
       
   169     }
       
   170 
       
   171     QString result;
       
   172     switch (dataType) {
       
   173         case REG_EXPAND_SZ:
       
   174         case REG_SZ: {
       
   175             result = QString::fromWCharArray(((const wchar_t *)data.constData()));
       
   176             break;
       
   177         }
       
   178 
       
   179         case REG_MULTI_SZ: {
       
   180             QStringList l;
       
   181             int i = 0;
       
   182             for (;;) {
       
   183                 QString s = QString::fromWCharArray((const wchar_t *)data.constData() + i);
       
   184                 i += s.length() + 1;
       
   185 
       
   186                 if (s.isEmpty())
       
   187                     break;
       
   188                 l.append(s);
       
   189             }
       
   190             result = l.join(", ");
       
   191             break;
       
   192         }
       
   193 
       
   194         case REG_NONE:
       
   195         case REG_BINARY: {
       
   196             result = QString::fromWCharArray((const wchar_t *)data.constData(), data.size() / 2);
       
   197             break;
       
   198         }
       
   199 
       
   200         case REG_DWORD_BIG_ENDIAN:
       
   201         case REG_DWORD: {
       
   202             Q_ASSERT(data.size() == sizeof(int));
       
   203             int i;
       
   204             memcpy((char*)&i, data.constData(), sizeof(int));
       
   205             result = QString::number(i);
       
   206             break;
       
   207         }
       
   208 
       
   209         default:
       
   210             qWarning("QSettings: unknown data %d type in windows registry", dataType);
       
   211             break;
       
   212     }
       
   213 
       
   214     RegCloseKey(handle);
       
   215     return result;
       
   216 #endif
       
   217 }
       
   218 
       
   219 /*!
       
   220     Returns the qmakespec for the compiler detected on the system.
       
   221 */
       
   222 QString Environment::detectQMakeSpec()
       
   223 {
       
   224     QString spec;
       
   225     switch (detectCompiler()) {
       
   226     case CC_NET2008:
       
   227         spec = "win32-msvc2008";
       
   228         break;
       
   229     case CC_NET2005:
       
   230         spec = "win32-msvc2005";
       
   231         break;
       
   232     case CC_NET2003:
       
   233         spec = "win32-msvc2003";
       
   234         break;
       
   235     case CC_NET2002:
       
   236         spec = "win32-msvc2002";
       
   237         break;
       
   238     case CC_MSVC4:
       
   239     case CC_MSVC5:
       
   240     case CC_MSVC6:
       
   241         spec = "win32-msvc";
       
   242         break;
       
   243     case CC_INTEL:
       
   244         spec = "win32-icc";
       
   245         break;
       
   246     case CC_MINGW:
       
   247         spec = "win32-g++";
       
   248         break;
       
   249     case CC_BORLAND:
       
   250         spec = "win32-borland";
       
   251         break;
       
   252     default:
       
   253         break;
       
   254     }
       
   255 
       
   256     return spec;
       
   257 }
       
   258 
       
   259 /*!
       
   260     Returns the enum of the compiler which was detected on the system.
       
   261     The compilers are detected in the order as entered into the
       
   262     compiler_info list.
       
   263 
       
   264     If more than one compiler is found, CC_UNKNOWN is returned.
       
   265 */
       
   266 Compiler Environment::detectCompiler()
       
   267 {
       
   268 #ifndef Q_OS_WIN32
       
   269     return MSVC6; // Always generate MSVC 6.0 versions on other platforms
       
   270 #else
       
   271     if(detectedCompiler != CC_UNKNOWN)
       
   272         return detectedCompiler;
       
   273 
       
   274     int installed = 0;
       
   275 
       
   276     // Check for compilers in registry first, to see which version is in PATH
       
   277     QString paths = qgetenv("PATH");
       
   278     QStringList pathlist = paths.toLower().split(";");
       
   279     for(int i = 0; compiler_info[i].compiler; ++i) {
       
   280         QString productPath = readRegistryKey(HKEY_LOCAL_MACHINE, compiler_info[i].regKey).toLower();
       
   281         if (productPath.length()) {
       
   282             QStringList::iterator it;
       
   283             for(it = pathlist.begin(); it != pathlist.end(); ++it) {
       
   284                 if((*it).contains(productPath)) {
       
   285                     ++installed;
       
   286                     detectedCompiler = compiler_info[i].compiler;
       
   287                     break;
       
   288                 }
       
   289             }
       
   290         }
       
   291     }
       
   292 
       
   293     // Now just go looking for the executables, and accept any executable as the lowest version
       
   294     if (!installed) {
       
   295         for(int i = 0; compiler_info[i].compiler; ++i) {
       
   296             QString executable = QString(compiler_info[i].executable).toLower();
       
   297             if (executable.length() && Environment::detectExecutable(executable)) {
       
   298                 ++installed;
       
   299                 detectedCompiler = compiler_info[i].compiler;
       
   300                 break;
       
   301             }
       
   302         }
       
   303     }
       
   304 
       
   305     if (installed > 1) {
       
   306         cout << "Found more than one known compiler! Using \"" << compilerInfo(detectedCompiler)->compilerStr << "\"" << endl;
       
   307         detectedCompiler = CC_UNKNOWN;
       
   308     }
       
   309     return detectedCompiler;
       
   310 #endif
       
   311 };
       
   312 
       
   313 /*!
       
   314     Returns true if the \a executable could be loaded, else false.
       
   315     This means that the executable either is in the current directory
       
   316     or in the PATH.
       
   317 */
       
   318 bool Environment::detectExecutable(const QString &executable)
       
   319 {
       
   320     PROCESS_INFORMATION procInfo;
       
   321     memset(&procInfo, 0, sizeof(procInfo));
       
   322 
       
   323     STARTUPINFO startInfo;
       
   324     memset(&startInfo, 0, sizeof(startInfo));
       
   325     startInfo.cb = sizeof(startInfo);
       
   326 
       
   327     bool couldExecute = CreateProcess(0, (wchar_t*)executable.utf16(),
       
   328                                       0, 0, false,
       
   329                                       CREATE_NO_WINDOW | CREATE_SUSPENDED,
       
   330                                       0, 0, &startInfo, &procInfo);
       
   331 
       
   332     if (couldExecute) {
       
   333         CloseHandle(procInfo.hThread);
       
   334         TerminateProcess(procInfo.hProcess, 0);
       
   335         CloseHandle(procInfo.hProcess);
       
   336     }
       
   337     return couldExecute;
       
   338 }
       
   339 
       
   340 /*!
       
   341     Creates a commandling from \a program and it \a arguments,
       
   342     escaping characters that needs it.
       
   343 */
       
   344 static QString qt_create_commandline(const QString &program, const QStringList &arguments)
       
   345 {
       
   346     QString programName = program;
       
   347     if (!programName.startsWith("\"") && !programName.endsWith("\"") && programName.contains(" "))
       
   348         programName = "\"" + programName + "\"";
       
   349     programName.replace("/", "\\");
       
   350 
       
   351     QString args;
       
   352     // add the prgram as the first arrg ... it works better
       
   353     args = programName + " ";
       
   354     for (int i=0; i<arguments.size(); ++i) {
       
   355         QString tmp = arguments.at(i);
       
   356         // in the case of \" already being in the string the \ must also be escaped
       
   357         tmp.replace( "\\\"", "\\\\\"" );
       
   358         // escape a single " because the arguments will be parsed
       
   359         tmp.replace( "\"", "\\\"" );
       
   360         if (tmp.isEmpty() || tmp.contains(' ') || tmp.contains('\t')) {
       
   361             // The argument must not end with a \ since this would be interpreted
       
   362             // as escaping the quote -- rather put the \ behind the quote: e.g.
       
   363             // rather use "foo"\ than "foo\"
       
   364             QString endQuote("\"");
       
   365             int i = tmp.length();
       
   366             while (i>0 && tmp.at(i-1) == '\\') {
       
   367                 --i;
       
   368                 endQuote += "\\";
       
   369             }
       
   370             args += QString(" \"") + tmp.left(i) + endQuote;
       
   371         } else {
       
   372             args += ' ' + tmp;
       
   373         }
       
   374     }
       
   375     return args;
       
   376 }
       
   377 
       
   378 /*!
       
   379     Creates a QByteArray of the \a environment.
       
   380 */
       
   381 static QByteArray qt_create_environment(const QStringList &environment)
       
   382 {
       
   383     QByteArray envlist;
       
   384     if (environment.isEmpty())
       
   385         return envlist;
       
   386 
       
   387     int pos = 0;
       
   388     // add PATH if necessary (for DLL loading)
       
   389     QByteArray path = qgetenv("PATH");
       
   390     if (environment.filter(QRegExp("^PATH=",Qt::CaseInsensitive)).isEmpty() && !path.isNull()) {
       
   391             QString tmp = QString(QLatin1String("PATH=%1")).arg(QString::fromLocal8Bit(path));
       
   392             uint tmpSize = sizeof(wchar_t) * (tmp.length() + 1);
       
   393             envlist.resize(envlist.size() + tmpSize);
       
   394             memcpy(envlist.data() + pos, tmp.utf16(), tmpSize);
       
   395             pos += tmpSize;
       
   396     }
       
   397     // add the user environment
       
   398     for (QStringList::ConstIterator it = environment.begin(); it != environment.end(); it++ ) {
       
   399             QString tmp = *it;
       
   400             uint tmpSize = sizeof(wchar_t) * (tmp.length() + 1);
       
   401             envlist.resize(envlist.size() + tmpSize);
       
   402             memcpy(envlist.data() + pos, tmp.utf16(), tmpSize);
       
   403             pos += tmpSize;
       
   404     }
       
   405     // add the 2 terminating 0 (actually 4, just to be on the safe side)
       
   406     envlist.resize(envlist.size() + 4);
       
   407     envlist[pos++] = 0;
       
   408     envlist[pos++] = 0;
       
   409     envlist[pos++] = 0;
       
   410     envlist[pos++] = 0;
       
   411 
       
   412     return envlist;
       
   413 }
       
   414 
       
   415 /*!
       
   416     Executes the command described in \a arguments, in the
       
   417     environment inherited from the parent process, with the
       
   418     \a additionalEnv settings applied.
       
   419     \a removeEnv removes the specified environment variables from
       
   420     the environment of the executed process.
       
   421 
       
   422     Returns the exit value of the process, or -1 if the command could
       
   423     not be executed.
       
   424 
       
   425     This function uses _(w)spawnvpe to spawn a process by searching
       
   426     through the PATH environment variable.
       
   427 */
       
   428 int Environment::execute(QStringList arguments, const QStringList &additionalEnv, const QStringList &removeEnv)
       
   429 {
       
   430 #ifdef CONFIGURE_DEBUG_EXECUTE
       
   431     qDebug() << "About to Execute: " << arguments;
       
   432     qDebug() << "   " << QDir::currentPath();
       
   433     qDebug() << "   " << additionalEnv;
       
   434     qDebug() << "   " << removeEnv;
       
   435 #endif
       
   436     // Create the full environment from the current environment and
       
   437     // the additionalEnv strings, then remove all variables defined
       
   438     // in removeEnv
       
   439     QMap<QString, QString> fullEnvMap;
       
   440     LPWSTR envStrings = GetEnvironmentStrings();
       
   441     if (envStrings) {
       
   442         int strLen = 0;
       
   443         for (LPWSTR envString = envStrings; *(envString); envString += strLen + 1) {
       
   444             strLen = wcslen(envString);
       
   445             QString str = QString((const QChar*)envString, strLen);
       
   446             if (!str.startsWith("=")) { // These are added by the system
       
   447                 int sepIndex = str.indexOf('=');
       
   448                 fullEnvMap.insert(str.left(sepIndex).toUpper(), str.mid(sepIndex +1));
       
   449             }
       
   450         }
       
   451     }
       
   452     FreeEnvironmentStrings(envStrings);
       
   453 
       
   454     // Add additionalEnv variables
       
   455     for (int i = 0; i < additionalEnv.count(); ++i) {
       
   456         const QString &str = additionalEnv.at(i);
       
   457         int sepIndex = str.indexOf('=');
       
   458         fullEnvMap.insert(str.left(sepIndex).toUpper(), str.mid(sepIndex +1));
       
   459     }
       
   460 
       
   461     // Remove removeEnv variables
       
   462     for (int j = 0; j < removeEnv.count(); ++j)
       
   463         fullEnvMap.remove(removeEnv.at(j).toUpper());
       
   464 
       
   465     // Add all variables to a QStringList
       
   466     QStringList fullEnv;
       
   467     QMapIterator<QString, QString> it(fullEnvMap);
       
   468     while (it.hasNext()) {
       
   469         it.next();
       
   470         fullEnv += QString(it.key() + "=" + it.value());
       
   471     }
       
   472 
       
   473     // ----------------------------
       
   474     QString program = arguments.takeAt(0);
       
   475     QString args = qt_create_commandline(program, arguments);
       
   476     QByteArray envlist = qt_create_environment(fullEnv);
       
   477 
       
   478     DWORD exitCode = -1;
       
   479     PROCESS_INFORMATION procInfo;
       
   480     memset(&procInfo, 0, sizeof(procInfo));
       
   481 
       
   482     STARTUPINFO startInfo;
       
   483     memset(&startInfo, 0, sizeof(startInfo));
       
   484     startInfo.cb = sizeof(startInfo);
       
   485 
       
   486     bool couldExecute = CreateProcess(0, (wchar_t*)args.utf16(),
       
   487                                       0, 0, true, CREATE_UNICODE_ENVIRONMENT,
       
   488                                       envlist.isEmpty() ? 0 : envlist.data(),
       
   489                                       0, &startInfo, &procInfo);
       
   490 
       
   491     if (couldExecute) {
       
   492         WaitForSingleObject(procInfo.hProcess, INFINITE);
       
   493         GetExitCodeProcess(procInfo.hProcess, &exitCode);
       
   494         CloseHandle(procInfo.hThread);
       
   495         CloseHandle(procInfo.hProcess);
       
   496     }
       
   497 
       
   498 
       
   499     if (exitCode == -1) {
       
   500         switch(GetLastError()) {
       
   501         case E2BIG:
       
   502             cerr << "execute: Argument list exceeds 1024 bytes" << endl;
       
   503             foreach(QString arg, arguments)
       
   504                 cerr << "   (" << arg.toLocal8Bit().constData() << ")" << endl;
       
   505             break;
       
   506         case ENOENT:
       
   507             cerr << "execute: File or path is not found (" << program.toLocal8Bit().constData() << ")" << endl;
       
   508             break;
       
   509         case ENOEXEC:
       
   510             cerr << "execute: Specified file is not executable or has invalid executable-file format (" << program.toLocal8Bit().constData() << ")" << endl;
       
   511             break;
       
   512         case ENOMEM:
       
   513             cerr << "execute: Not enough memory is available to execute new process." << endl;
       
   514             break;
       
   515         default:
       
   516             cerr << "execute: Unknown error" << endl;
       
   517             foreach(QString arg, arguments)
       
   518                 cerr << "   (" << arg.toLocal8Bit().constData() << ")" << endl;
       
   519             break;
       
   520         }
       
   521     }
       
   522     return exitCode;
       
   523 }
       
   524 
       
   525 bool Environment::cpdir(const QString &srcDir, const QString &destDir)
       
   526 {
       
   527     QString cleanSrcName = QDir::cleanPath(srcDir);
       
   528     QString cleanDstName = QDir::cleanPath(destDir);
       
   529 #ifdef CONFIGURE_DEBUG_CP_DIR
       
   530     qDebug() << "Attempt to cpdir " << cleanSrcName << "->" << cleanDstName;
       
   531 #endif
       
   532     if(!QFile::exists(cleanDstName) && !QDir().mkpath(cleanDstName)) {
       
   533 	qDebug() << "cpdir: Failure to create " << cleanDstName;
       
   534 	return false;
       
   535     }
       
   536 
       
   537     bool result = true;
       
   538     QDir dir = QDir(cleanSrcName);
       
   539     QFileInfoList allEntries = dir.entryInfoList(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
       
   540     for (int i = 0; result && (i < allEntries.count()); ++i) {
       
   541         QFileInfo entry = allEntries.at(i);
       
   542 	bool intermediate = true;
       
   543         if (entry.isDir()) {
       
   544             intermediate = cpdir(QString("%1/%2").arg(cleanSrcName).arg(entry.fileName()),
       
   545                             QString("%1/%2").arg(cleanDstName).arg(entry.fileName()));
       
   546         } else {
       
   547             QString destFile = QString("%1/%2").arg(cleanDstName).arg(entry.fileName());
       
   548 #ifdef CONFIGURE_DEBUG_CP_DIR
       
   549 	    qDebug() << "About to cp (file)" << entry.absoluteFilePath() << "->" << destFile;
       
   550 #endif
       
   551 	    QFile::remove(destFile);
       
   552             intermediate = QFile::copy(entry.absoluteFilePath(), destFile);
       
   553             SetFileAttributes((wchar_t*)destFile.utf16(), FILE_ATTRIBUTE_NORMAL);
       
   554         }
       
   555 	if(!intermediate) {
       
   556 	    qDebug() << "cpdir: Failure for " << entry.fileName() << entry.isDir();
       
   557 	    result = false;
       
   558 	}
       
   559     }
       
   560     return result;
       
   561 }
       
   562 
       
   563 bool Environment::rmdir(const QString &name)
       
   564 {
       
   565     bool result = true;
       
   566     QString cleanName = QDir::cleanPath(name);
       
   567 
       
   568     QDir dir = QDir(cleanName);
       
   569     QFileInfoList allEntries = dir.entryInfoList(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
       
   570     for (int i = 0; result && (i < allEntries.count()); ++i) {
       
   571         QFileInfo entry = allEntries.at(i);
       
   572         if (entry.isDir()) {
       
   573             result &= rmdir(entry.absoluteFilePath());
       
   574         } else {
       
   575             result &= QFile::remove(entry.absoluteFilePath());
       
   576         }
       
   577     }
       
   578     result &= dir.rmdir(cleanName);
       
   579     return result;
       
   580 }
       
   581 
       
   582 QT_END_NAMESPACE