tools/qtestlib/wince/cetest/activesyncconnection.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 "activesyncconnection.h"
       
    43 #include <qdir.h>
       
    44 #include <qfile.h>
       
    45 #include <qfileinfo>
       
    46 #include <rapi.h>
       
    47 
       
    48 extern void debugOutput(const QString& text, int level);
       
    49 
       
    50 ActiveSyncConnection::ActiveSyncConnection()
       
    51         : AbstractRemoteConnection()
       
    52         , connected(false)
       
    53 {
       
    54 }
       
    55 
       
    56 ActiveSyncConnection::~ActiveSyncConnection()
       
    57 {
       
    58     if (isConnected())
       
    59         disconnect();
       
    60 }
       
    61 
       
    62 bool ActiveSyncConnection::connect(QVariantList&)
       
    63 {
       
    64     if (connected)
       
    65         return true;
       
    66     connected = false;
       
    67     RAPIINIT init;
       
    68     init.cbSize = sizeof(init);
       
    69     if (CeRapiInitEx(&init) != S_OK)
       
    70         return connected;
       
    71 
       
    72     DWORD res;
       
    73     res = WaitForMultipleObjects(1,&(init.heRapiInit),true, 5000);
       
    74     if ((res == -1) || (res == WAIT_TIMEOUT) || (init.hrRapiInit != S_OK))
       
    75         return connected;
       
    76 
       
    77     connected = true;
       
    78     return connected;
       
    79 }
       
    80 
       
    81 void ActiveSyncConnection::disconnect()
       
    82 {
       
    83     connected = false;
       
    84     CeRapiUninit();
       
    85 }
       
    86 
       
    87 bool ActiveSyncConnection::isConnected() const
       
    88 {
       
    89     return connected;
       
    90 }
       
    91 
       
    92 bool ActiveSyncConnection::copyFileToDevice(const QString &localSource, const QString &deviceDest, bool failIfExists)
       
    93 {
       
    94     if (failIfExists) {
       
    95         CE_FIND_DATA search;
       
    96         HANDLE searchHandle = CeFindFirstFile(deviceDest.utf16(), &search);
       
    97         if (searchHandle != INVALID_HANDLE_VALUE) {
       
    98             CeFindClose(searchHandle);
       
    99             return false;
       
   100         }
       
   101     }
       
   102 
       
   103     QFile file(localSource);
       
   104     if (!file.exists())
       
   105         return false;
       
   106     if (!file.open(QIODevice::ReadOnly)) {
       
   107         debugOutput(QString::fromLatin1("  Could not open source file"),2);
       
   108         if (file.size() == 0) {
       
   109             // Create an empy file
       
   110             deleteFile(deviceDest);
       
   111             HANDLE deviceHandle = CeCreateFile(deviceDest.utf16(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
       
   112             if (deviceHandle != INVALID_HANDLE_VALUE) {
       
   113                 CeCloseHandle(deviceHandle);
       
   114                 return true;
       
   115             }
       
   116         } else {
       
   117             qWarning("Could not open %s: %s", qPrintable(localSource), qPrintable(file.errorString()));
       
   118         }
       
   119         return false;
       
   120     }
       
   121 
       
   122     deleteFile(deviceDest);
       
   123     HANDLE deviceHandle = CeCreateFile(deviceDest.utf16(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
       
   124     if (deviceHandle == INVALID_HANDLE_VALUE) {
       
   125         qWarning("Could not create %s: %s", qPrintable(deviceDest), strwinerror(CeGetLastError()).constData());
       
   126         return false;
       
   127     }
       
   128 
       
   129     DWORD written = 0;
       
   130     int currentPos = 0;
       
   131     int size = file.size();
       
   132     DWORD toWrite = 0;
       
   133     const int bufferSize = 65000;
       
   134     QByteArray data;
       
   135     data.reserve(bufferSize);
       
   136     while (currentPos < size) {
       
   137         data = file.read(bufferSize);
       
   138         if (data.size() <= 0) {
       
   139             wprintf( L"Error while reading file!\n");
       
   140             return false;
       
   141         }
       
   142         if (size - currentPos > bufferSize )
       
   143             toWrite = bufferSize;
       
   144         else
       
   145             toWrite = size - currentPos;
       
   146         if (toWrite == 0)
       
   147             break;
       
   148         if (!CeWriteFile(deviceHandle, data.data() , toWrite, &written, NULL)) {
       
   149             qWarning("Could not write to %s: %s", qPrintable(deviceDest), strwinerror(CeGetLastError()).constData());
       
   150             return false;
       
   151         }
       
   152         currentPos += written;
       
   153         data.clear();
       
   154         wprintf( L"%s -> %s (%d / %d) %d %%\r", localSource.utf16() , deviceDest.utf16(), currentPos , size, (100*currentPos)/size );
       
   155     }
       
   156     wprintf(L"\n");
       
   157 
       
   158     // Copy FileTime for update verification
       
   159     FILETIME creationTime, accessTime, writeTime;
       
   160     HANDLE localHandle = CreateFile(localSource.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
       
   161     if (localHandle != INVALID_HANDLE_VALUE) {
       
   162         if (GetFileTime(localHandle, &creationTime, &accessTime, &writeTime)) {
       
   163             LocalFileTimeToFileTime(&writeTime, &writeTime);
       
   164             if (!CeSetFileTime(deviceHandle, &writeTime, NULL, NULL)) {
       
   165                 debugOutput(QString::fromLatin1("  Could not write time values"), 0);
       
   166             }
       
   167         }
       
   168         CloseHandle(localHandle);
       
   169     }
       
   170     CeCloseHandle(deviceHandle);
       
   171 
       
   172     DWORD attributes = GetFileAttributes(localSource.utf16());
       
   173     if (attributes != -1 )
       
   174         CeSetFileAttributes(deviceDest.utf16(), attributes);
       
   175     return true;
       
   176 }
       
   177 
       
   178 bool ActiveSyncConnection::copyDirectoryToDevice(const QString &localSource, const QString &deviceDest, bool recursive)
       
   179 {
       
   180     QDir dir(localSource);
       
   181     if (!dir.exists())
       
   182         return false;
       
   183 
       
   184     deleteDirectory(deviceDest, recursive);
       
   185     CeCreateDirectory(deviceDest.utf16(), NULL);
       
   186     foreach(QString entry, dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot)) {
       
   187         QString source = localSource + "\\" + entry;
       
   188         QString target = deviceDest + "\\" + entry;
       
   189         QFileInfo info(source);
       
   190         if (info.isDir()) {
       
   191             if (recursive) {
       
   192                 if (!copyDirectoryToDevice(source, target, recursive))
       
   193                     return false;
       
   194             }
       
   195         } else {
       
   196             if (!copyFileToDevice(source, target))
       
   197                 return false;
       
   198         }
       
   199     }
       
   200     return true;
       
   201 }
       
   202 
       
   203 bool ActiveSyncConnection::copyFileFromDevice(const QString &deviceSource, const QString &localDest, bool failIfExists)
       
   204 {
       
   205     QFile target(localDest);
       
   206     if (failIfExists && target.exists()) {
       
   207         debugOutput(QString::fromLatin1("  Not allowed to overwrite file"), 2);
       
   208         return false;
       
   209     }
       
   210 
       
   211     if (target.exists())
       
   212         target.remove();
       
   213 
       
   214     HANDLE deviceHandle = CeCreateFile(deviceSource.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
       
   215     if (deviceHandle == INVALID_HANDLE_VALUE) {
       
   216         debugOutput(QString::fromLatin1("  Could not open file on device"), 2);
       
   217         return false;
       
   218     }
       
   219 
       
   220     DWORD fileSize = CeGetFileSize( deviceHandle, NULL );
       
   221     if (fileSize == -1) {
       
   222         debugOutput(QString::fromLatin1("  Could not stat filesize of remote file"), 2);
       
   223         CeCloseHandle(deviceHandle);
       
   224         return false;
       
   225     }
       
   226 
       
   227     if (!target.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
       
   228         debugOutput(QString::fromLatin1("  Could not open local file for writing"), 2);
       
   229         CeCloseHandle(deviceHandle);
       
   230         return false;
       
   231     }
       
   232 
       
   233     int bufferSize = 65000;
       
   234     char *buffer = (char*) malloc(bufferSize);
       
   235     DWORD bufferRead = 0;
       
   236     DWORD bufferWritten = 0;
       
   237     bool readUntilEnd = false;
       
   238     while(CeReadFile(deviceHandle, buffer, bufferSize, &bufferRead, NULL)) {
       
   239         if (bufferRead == 0) {
       
   240             readUntilEnd = true;
       
   241             break;
       
   242         }
       
   243         target.write(buffer, bufferRead);
       
   244         bufferWritten += bufferRead;
       
   245         wprintf(L"%s -> %s (%d / %d) %d %%\r", deviceSource.utf16(), localDest.utf16(), bufferWritten, fileSize, (100*bufferWritten)/fileSize);
       
   246     }
       
   247     wprintf(L"\n");
       
   248 
       
   249     if (!readUntilEnd) {
       
   250         debugOutput(QString::fromLatin1("  an error occured during copy"), 2);
       
   251         return false;
       
   252     }
       
   253 
       
   254     CeCloseHandle(deviceHandle);
       
   255     return true;
       
   256 }
       
   257 
       
   258 bool ActiveSyncConnection::copyDirectoryFromDevice(const QString &deviceSource, const QString &localDest, bool recursive)
       
   259 {
       
   260     if (!QDir(localDest).exists() && !QDir(localDest).mkpath(QDir(localDest).absolutePath())) {
       
   261         debugOutput(QString::fromLatin1("  Could not create local path"), 2);
       
   262     }
       
   263 
       
   264     QString searchArg = deviceSource + "\\*";
       
   265     CE_FIND_DATA data;
       
   266     HANDLE searchHandle = CeFindFirstFile(searchArg.utf16(), &data);
       
   267     if (searchHandle == INVALID_HANDLE_VALUE) {
       
   268         // We return true because we might be in a recursive call
       
   269         // where nothing is to copy and the copy process
       
   270         // might still be correct
       
   271         return true;
       
   272     }
       
   273 
       
   274     do {
       
   275         QString srcFile = deviceSource + "\\" + QString::fromWCharArray(data.cFileName);
       
   276         QString destFile = localDest + "\\" + QString::fromWCharArray(data.cFileName);
       
   277         if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
       
   278             if (recursive && !copyDirectoryFromDevice(srcFile, destFile, recursive)) {
       
   279                 wprintf(L"Copy of subdirectory(%s) failed\n", srcFile.utf16());
       
   280                 return false;
       
   281             }
       
   282         } else {
       
   283             copyFileFromDevice(srcFile, destFile, false);
       
   284         }
       
   285     } while(CeFindNextFile(searchHandle, &data));
       
   286     CeFindClose(searchHandle);
       
   287     return true;
       
   288 }
       
   289 
       
   290 bool ActiveSyncConnection::copyFile(const QString &srcFile, const QString &destFile, bool failIfExists)
       
   291 {
       
   292     return CeCopyFile(QDir::toNativeSeparators(srcFile).utf16(),
       
   293                       QDir::toNativeSeparators(destFile).utf16(), failIfExists);
       
   294 }
       
   295 
       
   296 bool ActiveSyncConnection::copyDirectory(const QString &srcDirectory, const QString &destDirectory,
       
   297                                       bool recursive)
       
   298 {
       
   299     CeCreateDirectory(destDirectory.utf16(), NULL);
       
   300     QString searchArg = srcDirectory + "\\*";
       
   301     CE_FIND_DATA data;
       
   302     HANDLE searchHandle = CeFindFirstFile(searchArg.utf16(), &data);
       
   303     if (searchHandle == INVALID_HANDLE_VALUE) {
       
   304         // We return true because we might be in a recursive call
       
   305         // where nothing is to copy and the copy process
       
   306         // might still be correct
       
   307         return true;
       
   308     }
       
   309 
       
   310     do {
       
   311         QString srcFile = srcDirectory + "\\" + QString::fromWCharArray(data.cFileName);
       
   312         QString destFile = destDirectory + "\\" + QString::fromWCharArray(data.cFileName);
       
   313         if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
       
   314             if (recursive && !copyDirectory(srcFile, destFile, recursive)) {
       
   315                 wprintf(L"Copy of subdirectory(%s) failed\n", srcFile.utf16());
       
   316                 return false;
       
   317             }
       
   318         } else {
       
   319             debugOutput(QString::fromLatin1("Copy %1 -> %2\n").arg(srcFile).arg(destFile), 0);
       
   320             CeCopyFile(srcFile.utf16(), destFile.utf16(), false);
       
   321         }
       
   322     } while(CeFindNextFile(searchHandle, &data));
       
   323     CeFindClose(searchHandle);
       
   324     return true;
       
   325 }
       
   326 
       
   327 bool ActiveSyncConnection::deleteFile(const QString &fileName)
       
   328 {
       
   329     CeSetFileAttributes(fileName.utf16(), FILE_ATTRIBUTE_NORMAL);
       
   330     return CeDeleteFile(fileName.utf16());
       
   331 }
       
   332 
       
   333 bool ActiveSyncConnection::deleteDirectory(const QString &directory, bool recursive, bool failIfContentExists)
       
   334 {
       
   335     HANDLE hFind;
       
   336     CE_FIND_DATA FindFileData;
       
   337     QString FileName = directory + "\\*";
       
   338     hFind = CeFindFirstFile(FileName.utf16(), &FindFileData);
       
   339     if( hFind == INVALID_HANDLE_VALUE )
       
   340         return CeRemoveDirectory(directory.utf16());
       
   341 
       
   342     if (failIfContentExists)
       
   343         return false;
       
   344 
       
   345     do {
       
   346         QString FileName = directory + "\\" + QString::fromWCharArray(FindFileData.cFileName);
       
   347         if((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
       
   348             if (recursive)
       
   349                 if (!deleteDirectory(FileName, recursive, failIfContentExists))
       
   350                     return false;
       
   351         } else {
       
   352             if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
       
   353                 CeSetFileAttributes(FileName.utf16(), FILE_ATTRIBUTE_NORMAL);
       
   354             if( !CeDeleteFile(FileName.utf16()) )
       
   355                 break;
       
   356         }
       
   357     } while(CeFindNextFile(hFind,&FindFileData));
       
   358     CeFindClose(hFind);
       
   359 
       
   360     return CeRemoveDirectory(directory.utf16());
       
   361 }
       
   362 
       
   363 bool ActiveSyncConnection::execute(QString program, QString arguments, int timeout, int *returnValue)
       
   364 {
       
   365     if (!isConnected()) {
       
   366         qWarning("Cannot execute, connect to device first!");
       
   367         return false;
       
   368     }
       
   369 
       
   370     PROCESS_INFORMATION* pid = new PROCESS_INFORMATION;
       
   371     bool result = false;
       
   372     if (timeout != 0) {
       
   373         // If we want to wait, we have to use CeRapiInvoke, as CeCreateProcess has no way to wait
       
   374         // until the process ends. The lib must have been build and also deployed already.
       
   375         if (!isConnected() && !connect())
       
   376             return false;
       
   377 
       
   378         QString dllLocation = "\\Windows\\QtRemote.dll";
       
   379         QString functionName = "qRemoteLaunch";
       
   380 
       
   381         DWORD outputSize;
       
   382         BYTE* output;
       
   383         IRAPIStream *stream;
       
   384         int returned = 0;
       
   385         DWORD error = 0;
       
   386         HRESULT res = CeRapiInvoke(dllLocation.utf16(), functionName.utf16(), 0, 0, &outputSize, &output, &stream, 0);
       
   387         if (S_OK != res) {
       
   388             DWORD ce_error = CeGetLastError();
       
   389             if (S_OK != ce_error) {
       
   390                 qWarning("Error invoking %s on %s: %s", qPrintable(functionName),
       
   391                     qPrintable(dllLocation), strwinerror(ce_error).constData());
       
   392             } else {
       
   393                 qWarning("Error: %s on %s unexpectedly returned %d", qPrintable(functionName),
       
   394                     qPrintable(dllLocation), res);
       
   395             }
       
   396         } else {
       
   397             DWORD written;
       
   398             int strSize = program.length();
       
   399             if (S_OK != stream->Write(&strSize, sizeof(strSize), &written)) {
       
   400                 qWarning("   Could not write appSize to process");
       
   401                 return false;
       
   402             }
       
   403             if (S_OK != stream->Write(program.utf16(), program.length()*sizeof(wchar_t), &written)) {
       
   404                 qWarning("   Could not write appName to process");
       
   405                 return false;
       
   406             }
       
   407             strSize = arguments.length();
       
   408             if (S_OK != stream->Write(&strSize, sizeof(strSize), &written)) {
       
   409                 qWarning("   Could not write argumentSize to process");
       
   410                 return false;
       
   411             }
       
   412             if (S_OK != stream->Write(arguments.utf16(), arguments.length()*sizeof(wchar_t), &written)) {
       
   413                 qWarning("   Could not write arguments to process");
       
   414                 return false;
       
   415             }
       
   416             if (S_OK != stream->Write(&timeout, sizeof(timeout), &written)) {
       
   417                 qWarning("   Could not write waiting option to process");
       
   418                 return false;
       
   419             }
       
   420 
       
   421             if (S_OK != stream->Read(&returned, sizeof(returned), &written)) {
       
   422                 qWarning("   Could not access return value of process");
       
   423             }
       
   424             if (S_OK != stream->Read(&error, sizeof(error), &written)) {
       
   425                 qWarning("   Could not access error code");
       
   426             }
       
   427 
       
   428             if (error) {
       
   429                 qWarning("Error on target: %s", strwinerror(error).constData());
       
   430                 result = false;
       
   431             }
       
   432             else {
       
   433                 result = true;
       
   434             }
       
   435         }
       
   436 
       
   437         if (returnValue)
       
   438             *returnValue = returned;
       
   439     } else {
       
   440         // We do not need to invoke another lib etc, if we are not interested in results anyway...
       
   441         result = CeCreateProcess(program.utf16(), arguments.utf16(), 0, 0, false, 0, 0, 0, 0, pid);
       
   442     }
       
   443     return result;
       
   444 }
       
   445 
       
   446 bool ActiveSyncConnection::createDirectory(const QString &path, bool deleteBefore)
       
   447 {
       
   448     if (deleteBefore)
       
   449         deleteDirectory(path);
       
   450     QStringList separated = path.split(QLatin1Char('\\'));
       
   451     QString current = QLatin1String("\\");
       
   452     bool result;
       
   453     for (int i=1; i < separated.size(); ++i) {
       
   454         current += separated.at(i);
       
   455         result = CeCreateDirectory(current.utf16(), NULL);
       
   456         current += QLatin1String("\\");
       
   457     }
       
   458     return result;
       
   459 }
       
   460 
       
   461 bool ActiveSyncConnection::timeStampForLocalFileTime(FILETIME* fTime) const
       
   462 {
       
   463     QString tmpFile = QString::fromLatin1("\\qt_tmp_ftime_convert");
       
   464     HANDLE remoteHandle = CeCreateFile(tmpFile.utf16(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
       
   465     if (remoteHandle == INVALID_HANDLE_VALUE)
       
   466         return false;
       
   467 
       
   468     LocalFileTimeToFileTime(fTime, fTime);
       
   469 
       
   470     if (!CeSetFileTime(remoteHandle, fTime, NULL, NULL)) {
       
   471         CeCloseHandle(remoteHandle);
       
   472         return false;
       
   473     }
       
   474 
       
   475     CeCloseHandle(remoteHandle);
       
   476     remoteHandle = CeCreateFile(tmpFile.utf16(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
       
   477     if (remoteHandle == INVALID_HANDLE_VALUE)
       
   478         return false;
       
   479     if (!CeGetFileTime(remoteHandle, fTime, NULL, NULL)) {
       
   480         CeCloseHandle(remoteHandle);
       
   481         return false;
       
   482     }
       
   483 
       
   484     CeCloseHandle(remoteHandle);
       
   485     CeDeleteFile(tmpFile.utf16());
       
   486     return true;
       
   487 }
       
   488 
       
   489 bool ActiveSyncConnection::fileCreationTime(const QString &fileName, FILETIME* deviceCreationTime) const
       
   490 {
       
   491     HANDLE deviceHandle = CeCreateFile(fileName.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
       
   492     if (deviceHandle == INVALID_HANDLE_VALUE)
       
   493         return false;
       
   494 
       
   495     bool result = true;
       
   496     if (!CeGetFileTime(deviceHandle, deviceCreationTime, NULL, NULL))
       
   497         result = false;
       
   498 
       
   499     CeCloseHandle(deviceHandle);
       
   500     return result;
       
   501 }