2014-05-16 11:33:57 +00:00
/*
The MIT License ( MIT )
Copyright ( c ) 2013 The ioquake Group
Permission is hereby granted , free of charge , to any person obtaining a copy of
this software and associated documentation files ( the " Software " ) , to deal in
the Software without restriction , including without limitation the rights to
use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies of
the Software , and to permit persons to whom the Software is furnished to do so ,
subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY , FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER
IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
*/
2014-05-16 12:41:57 +00:00
# include <time.h>
2014-05-16 11:33:57 +00:00
# include <QFile>
# include <QFileInfo>
# include "filecopy.h"
2014-05-16 12:41:57 +00:00
QString FileUtils : : uniqueFilename ( const QString & filename )
{
QString unique ;
for ( ; ; )
{
QFileInfo fi ( filename ) ;
unique = fi . path ( ) + QString ( " / " ) + QString : : number ( qrand ( ) , 16 ) + QString ( " _ " ) + fi . fileName ( ) ;
if ( ! QFile : : exists ( unique ) )
break ;
}
return unique ;
}
2014-05-18 11:41:54 +00:00
QString FileUtils : : completeTransaction ( const QList < FileOperation > & renameOperations )
{
for ( int i = 0 ; i < renameOperations . size ( ) ; i + + )
{
const FileOperation & fo = renameOperations . at ( i ) ;
const QString randomDest = FileUtils : : uniqueFilename ( fo . dest ) ;
// Rename dest to random.
if ( ! QFile : : rename ( fo . dest , randomDest ) )
{
return QString ( " Transaction error renaming '%1' to '%2' " ) . arg ( fo . dest ) . arg ( randomDest ) ;
}
// Rename source to dest.
if ( ! QFile : : rename ( fo . source , fo . dest ) )
{
return QString ( " Transaction error renaming '%1' to '%2' " ) . arg ( fo . source ) . arg ( fo . dest ) ;
}
// Delete random.
QFile : : remove ( randomDest ) ;
}
return QString ( ) ;
}
2014-05-16 12:41:57 +00:00
FileCopyWorker : : FileCopyWorker ( const QList < FileOperation > & files ) : files ( files ) , isCancelled ( false )
2014-05-16 11:33:57 +00:00
{
}
void FileCopyWorker : : copy ( )
{
2014-05-16 12:41:57 +00:00
qsrand ( time ( NULL ) ) ;
2014-05-16 11:33:57 +00:00
for ( int i = 0 ; i < files . size ( ) ; i + + )
{
QFile sourceFile ( files . at ( i ) . source ) ;
if ( ! sourceFile . open ( QIODevice : : ReadOnly ) )
{
emit errorMessage ( QString ( " '%1': %2 " ) . arg ( files . at ( i ) . source ) . arg ( sourceFile . errorString ( ) ) ) ;
2014-05-16 12:41:57 +00:00
goto cleanup ;
2014-05-16 11:33:57 +00:00
}
2014-05-17 04:26:26 +00:00
// Write to the destination file if it doesn't exist, otherwise write to a uniquely named file.
const bool destExists = QFile : : exists ( files . at ( i ) . dest ) ;
QString destFilename ;
if ( destExists )
{
destFilename = FileUtils : : uniqueFilename ( files . at ( i ) . dest ) ;
}
else
{
destFilename = files . at ( i ) . dest ;
}
QFile destinationFile ( destFilename ) ;
2014-05-16 11:33:57 +00:00
if ( ! destinationFile . open ( QIODevice : : WriteOnly ) )
{
2014-05-17 04:26:26 +00:00
emit errorMessage ( QString ( " '%1': %2 " ) . arg ( destFilename ) . arg ( destinationFile . errorString ( ) ) ) ;
2014-05-16 12:41:57 +00:00
goto cleanup ;
2014-05-16 11:33:57 +00:00
}
2014-05-17 04:26:26 +00:00
// Don't add a rename operation if the destination file doesn't exist - not trying to overwrite, don't need to rename anything to complete the transaction.
if ( destExists )
{
FileOperation fo ;
fo . source = destFilename ;
fo . dest = files . at ( i ) . dest ;
renameOperations . append ( fo ) ;
}
2014-05-16 12:41:57 +00:00
2014-05-16 11:33:57 +00:00
emit fileChanged ( QFileInfo ( sourceFile . fileName ( ) ) . fileName ( ) ) ;
const qint64 totalBytes = sourceFile . size ( ) ;
qint64 totalBytesWritten = 0 ;
for ( ; ; )
{
const qint64 bytesRead = sourceFile . read ( buffer , bufferSize ) ;
if ( bytesRead = = 0 )
break ;
const qint64 bytesWritten = destinationFile . write ( buffer , bytesRead ) ;
totalBytesWritten + = bytesWritten ;
emit progressChanged ( totalBytesWritten , totalBytes ) ;
QMutexLocker locker ( & cancelMutex ) ;
if ( isCancelled )
2014-05-16 12:41:57 +00:00
goto cleanup ;
2014-05-16 11:33:57 +00:00
}
2014-05-16 12:41:57 +00:00
2014-05-16 11:33:57 +00:00
}
2014-05-16 12:41:57 +00:00
emit copyFinished ( renameOperations ) ;
return ;
// Delete all the destination files.
cleanup :
for ( int i = 0 ; i < renameOperations . size ( ) ; i + + )
{
QFile : : remove ( renameOperations . at ( i ) . source ) ;
}
2014-05-16 11:33:57 +00:00
}
void FileCopyWorker : : cancel ( )
{
QMutexLocker locker ( & cancelMutex ) ;
isCancelled = true ;
}