source: trunk/tools/qtestlib/wince/cetest/activesyncconnection.cpp@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

  • Property svn:eol-style set to native
File size: 17.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the tools applications of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
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
48extern void debugOutput(const QString& text, int level);
49
50ActiveSyncConnection::ActiveSyncConnection()
51 : AbstractRemoteConnection()
52 , connected(false)
53{
54}
55
56ActiveSyncConnection::~ActiveSyncConnection()
57{
58 if (isConnected())
59 disconnect();
60}
61
62bool 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
81void ActiveSyncConnection::disconnect()
82{
83 connected = false;
84 CeRapiUninit();
85}
86
87bool ActiveSyncConnection::isConnected() const
88{
89 return connected;
90}
91
92bool 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
178bool 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
203bool 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
258bool 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
290bool 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
296bool 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
327bool ActiveSyncConnection::deleteFile(const QString &fileName)
328{
329 CeSetFileAttributes(fileName.utf16(), FILE_ATTRIBUTE_NORMAL);
330 return CeDeleteFile(fileName.utf16());
331}
332
333bool 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
363bool 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
446bool 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
461bool 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
489bool 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}
Note: See TracBrowser for help on using the repository browser.