|
|
|
/***************************************************************************
|
|
|
|
smb4ksynchronizer - This is the synchronizer of Smb4K.
|
|
|
|
-------------------
|
|
|
|
begin : Mo Jul 4 2005
|
|
|
|
copyright : (C) 2005-2007 by Alexander Reinholdt
|
|
|
|
email : dustpuppy@users.berlios.de
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
* This program is distributed in the hope that it will be useful, but *
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
|
|
* General Public License for more details. *
|
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
* along with this program; if not, write to the *
|
|
|
|
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
|
|
|
* MA 02110-1301 USA *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
// TQt includes
|
|
|
|
#include <tqlayout.h>
|
|
|
|
#include <tqdir.h>
|
|
|
|
#include <tqlabel.h>
|
|
|
|
#include <tqregexp.h>
|
|
|
|
|
|
|
|
// KDE includes
|
|
|
|
#include <tdemessagebox.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kdialogbase.h>
|
|
|
|
#include <klineedit.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <kprogress.h>
|
|
|
|
#include <kurlrequester.h>
|
|
|
|
#include <kguiitem.h>
|
|
|
|
#include <tdeapplication.h>
|
|
|
|
|
|
|
|
// application specific includes
|
|
|
|
#include "smb4ksynchronizer.h"
|
|
|
|
#include "smb4kdefs.h"
|
|
|
|
#include "smb4kerror.h"
|
|
|
|
#include "smb4tdeglobal.h"
|
|
|
|
#include "smb4kshare.h"
|
|
|
|
#include "smb4ksynchronizationinfo.h"
|
|
|
|
#include "smb4ksettings.h"
|
|
|
|
|
|
|
|
using namespace Smb4TDEGlobal;
|
|
|
|
|
|
|
|
bool cancel = false;
|
|
|
|
|
|
|
|
|
|
|
|
Smb4KSynchronizer::Smb4KSynchronizer( TQObject *parent, const char *name )
|
|
|
|
: TQObject( parent, name )
|
|
|
|
{
|
|
|
|
m_proc = new TDEProcess( this, "SynchronizerProcess" );
|
|
|
|
|
|
|
|
m_proc->setUseShell( true );
|
|
|
|
|
|
|
|
m_working = false;
|
|
|
|
|
|
|
|
connect( m_proc, TQ_SIGNAL( receivedStdout( TDEProcess *, char *, int ) ),
|
|
|
|
this, TQ_SLOT( slotReceivedStdout( TDEProcess *, char *, int ) ) );
|
|
|
|
|
|
|
|
connect( m_proc, TQ_SIGNAL( processExited( TDEProcess* ) ),
|
|
|
|
this, TQ_SLOT( slotProcessExited( TDEProcess * ) ) );
|
|
|
|
|
|
|
|
connect( m_proc, TQ_SIGNAL( receivedStderr( TDEProcess *, char *, int ) ),
|
|
|
|
this, TQ_SLOT( slotReceivedStderr( TDEProcess *, char *, int ) ) );
|
|
|
|
|
|
|
|
connect( kapp, TQ_SIGNAL( shutDown() ),
|
|
|
|
this, TQ_SLOT( slotShutdown() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Smb4KSynchronizer::~Smb4KSynchronizer()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
Synchronizes a share with a local copy or vice versa.
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void Smb4KSynchronizer::synchronize( const TQString &source, const TQString &destination )
|
|
|
|
{
|
|
|
|
if ( Smb4KSettings::rsync().isEmpty() )
|
|
|
|
{
|
|
|
|
Smb4KError::error( ERROR_COMMAND_NOT_FOUND, "rsync" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Do not stop here but buffer the requests and
|
|
|
|
// process them if the previous process finished.
|
|
|
|
if ( isRunning() )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_working = true;
|
|
|
|
emit state( SYNCHRONIZER_START );
|
|
|
|
emit start();
|
|
|
|
|
|
|
|
// We will only define the stuff we urgently need
|
|
|
|
// here. The options that actually influence rsync's
|
|
|
|
// behavior will be retrieved by readRsyncOptions().
|
|
|
|
TQString command = "rsync --progress ";
|
|
|
|
|
|
|
|
command.append( readRsyncOptions() );
|
|
|
|
command.append( " " );
|
|
|
|
command.append( TDEProcess::quote( source ) );
|
|
|
|
command.append( " " );
|
|
|
|
command.append( TDEProcess::quote( destination ) );
|
|
|
|
|
|
|
|
*m_proc << command;
|
|
|
|
|
|
|
|
// Use TDEProcess::OwnGroup instead of TDEProcess::NotifyOnExit here, because
|
|
|
|
// this garantees that the process is indeed killed when using abort().
|
|
|
|
// See TDEProcess docs for further information.
|
|
|
|
m_proc->start( TDEProcess::OwnGroup, TDEProcess::AllOutput );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
Reads the options that should be used with rsync
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
const TQString Smb4KSynchronizer::readRsyncOptions()
|
|
|
|
{
|
|
|
|
TQString options;
|
|
|
|
|
|
|
|
if ( Smb4KSettings::archiveMode() )
|
|
|
|
{
|
|
|
|
options.append( " --archive" );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
options.append( Smb4KSettings::recurseIntoDirectories() ?
|
|
|
|
" --recursive" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::preserveSymlinks() ?
|
|
|
|
" --links" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::preservePermissions() ?
|
|
|
|
" --perms" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::preserveTimes() ?
|
|
|
|
" --times" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::preserveGroup() ?
|
|
|
|
" --group" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::preserveOwner() ?
|
|
|
|
" --owner" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::preserveDevicesAndSpecials() ?
|
|
|
|
" --devices --specials" : // alias: -D
|
|
|
|
"" );
|
|
|
|
}
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::relativePathNames() ?
|
|
|
|
" --relative" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::omitDirectoryTimes() ?
|
|
|
|
" --omit-dir-times" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::noImpliedDirectories() ?
|
|
|
|
" --no-implied-dirs" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::updateTarget() ?
|
|
|
|
" --update" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::updateInPlace() ?
|
|
|
|
" --inplace" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::transferDirectories() ?
|
|
|
|
" --dirs" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::transformSymlinks() ?
|
|
|
|
" --copy-links" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::transformUnsafeSymlinks() ?
|
|
|
|
" --copy-unsafe-links" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::ignoreUnsafeSymlinks() ?
|
|
|
|
" --safe-links" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::preserveHardLinks() ?
|
|
|
|
" --hard-links" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::keepDirectorySymlinks() ?
|
|
|
|
" --keep-dirlinks" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::deleteExtraneous() ?
|
|
|
|
" --delete" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::removeSourceFiles() ?
|
|
|
|
" --remove-source-files" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::deleteBefore() ?
|
|
|
|
" --delete-before" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::deleteDuring() ?
|
|
|
|
" --delete-during" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::deleteAfter() ?
|
|
|
|
" --delete-after" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::deleteExcluded() ?
|
|
|
|
" --delete-excluded" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::ignoreErrors() ?
|
|
|
|
" --ignore-errors" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::forceDirectoryDeletion() ?
|
|
|
|
" --force" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::copyFilesWhole() ?
|
|
|
|
" --whole-file" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::efficientSparseFileHandling() ?
|
|
|
|
" --sparse" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::oneFileSystem() ?
|
|
|
|
" --one-file-system" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::updateExisting() ?
|
|
|
|
" --existing" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::ignoreExisting() ?
|
|
|
|
" --ignore-existing" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::delayUpdates() ?
|
|
|
|
" --delay-updates" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::compressData() ?
|
|
|
|
" --compress" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
if ( Smb4KSettings::makeBackups() )
|
|
|
|
{
|
|
|
|
options.append( " --backup" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::useBackupDirectory() ?
|
|
|
|
" --backup-dir="+Smb4KSettings::backupDirectory() :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::useBackupSuffix() ?
|
|
|
|
" --suffix="+Smb4KSettings::backupSuffix() :
|
|
|
|
"" );
|
|
|
|
}
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::useMaximumDelete() ?
|
|
|
|
" --max-delete="+TQString( "%1" ).arg( Smb4KSettings::maximumDeleteValue() ) :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::useChecksum() ?
|
|
|
|
" --checksum" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::useBlockSize() ?
|
|
|
|
" --block-size="+TQString( "%1" ).arg( Smb4KSettings::blockSize() ) :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::useChecksumSeed() ?
|
|
|
|
" --checksum-seed="+TQString( "%1" ).arg( Smb4KSettings::checksumSeed() ) :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
if ( !Smb4KSettings::customFilteringRules().isEmpty() )
|
|
|
|
{
|
|
|
|
options.append( " "+Smb4KSettings::customFilteringRules() );
|
|
|
|
}
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::useMinimalTransferSize() ?
|
|
|
|
" --min-size="+TQString( "%1" ).arg( Smb4KSettings::minimalTransferSize() )+"K" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::useMaximalTransferSize() ?
|
|
|
|
" --max-size="+TQString( "%1" ).arg( Smb4KSettings::maximalTransferSize() )+"K" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
if ( Smb4KSettings::keepPartial() )
|
|
|
|
{
|
|
|
|
options.append( " --partial" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::usePartialDirectory() ?
|
|
|
|
" --partial-dir="+Smb4KSettings::partialDirectory() :
|
|
|
|
"" );
|
|
|
|
}
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::useCVSExclude() ?
|
|
|
|
" --cvs-exclude" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::useFFilterRule() ?
|
|
|
|
" -F" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::useFFFilterRule() ?
|
|
|
|
" -F -F" :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::useExcludePattern() ?
|
|
|
|
" --exclude="+Smb4KSettings::excludePattern() :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::useExcludeFrom() ?
|
|
|
|
" --exclude-from="+Smb4KSettings::excludeFrom() :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::useIncludePattern() ?
|
|
|
|
" --include="+Smb4KSettings::includePattern() :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
options.append( Smb4KSettings::useIncludeFrom() ?
|
|
|
|
" --include-from="+Smb4KSettings::includeFrom() :
|
|
|
|
"" );
|
|
|
|
|
|
|
|
return options;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// SLOT IMPLEMENTATIONS
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void Smb4KSynchronizer::abort()
|
|
|
|
{
|
|
|
|
cancel = true;
|
|
|
|
|
|
|
|
if ( m_proc->isRunning() )
|
|
|
|
{
|
|
|
|
m_proc->kill();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Smb4KSynchronizer::slotProcessExited( TDEProcess * )
|
|
|
|
{
|
|
|
|
m_proc->clearArguments();
|
|
|
|
|
|
|
|
m_working = false;
|
|
|
|
|
|
|
|
emit finished();
|
|
|
|
emit state( SYNCHRONIZER_STOP );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Smb4KSynchronizer::slotReceivedStdout( TDEProcess *, char *buf, int len )
|
|
|
|
{
|
|
|
|
m_buffer = TQString::fromLocal8Bit( buf, len );
|
|
|
|
|
|
|
|
Smb4KSynchronizationInfo sync_info;
|
|
|
|
|
|
|
|
TQString partial, total, files, rate;
|
|
|
|
|
|
|
|
if ( m_buffer[0].isSpace() && m_buffer.contains( "/s ", true ) > 0 )
|
|
|
|
{
|
|
|
|
partial = m_buffer.section( "%", 0, 0 ).section( " ", -1, -1 ).stripWhiteSpace();
|
|
|
|
|
|
|
|
if ( !partial.isEmpty() )
|
|
|
|
{
|
|
|
|
sync_info.setIndividualProgress( partial.toInt() );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( m_buffer.contains( "to-check=" ) > 0 )
|
|
|
|
{
|
|
|
|
// Newer versions of rsync:
|
|
|
|
TQString tmp = m_buffer.section( "to-check=", 1, 1 ).section( ")", 0, 0 ).stripWhiteSpace();
|
|
|
|
|
|
|
|
if ( !tmp.isEmpty() )
|
|
|
|
{
|
|
|
|
double tmp_total = tmp.section( "/", 1, 1 ).stripWhiteSpace().toInt();
|
|
|
|
double tmp_done = tmp.section( "/", 0, 0 ).stripWhiteSpace().toInt();
|
|
|
|
double tmp_percent = ((tmp_total-tmp_done)/tmp_total)*100;
|
|
|
|
|
|
|
|
total = TQString( "%1" ).arg( tmp_percent ).section( ".", 0, 0 ).stripWhiteSpace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Older versions of rsync:
|
|
|
|
total = m_buffer.section( " (", 1, 1 ).section( ",", 1, 1 ).section( "%", 0, 0 ).section( ".", 0, 0 ).stripWhiteSpace();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !total.isEmpty() )
|
|
|
|
{
|
|
|
|
sync_info.setTotalProgress( total.toInt() );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( m_buffer.contains( "xfer#" ) > 0 )
|
|
|
|
{
|
|
|
|
// Newer versions of rsync:
|
|
|
|
files = m_buffer.section( "xfer#", 1, 1 ).section( ",", 0, 0 ).stripWhiteSpace();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Older versions of rsync:
|
|
|
|
files = m_buffer.section( " (", 1, 1 ).section( ",", 0, 0 ).stripWhiteSpace();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !files.isEmpty() )
|
|
|
|
{
|
|
|
|
sync_info.setProcessedFileNumber( files.toInt() );
|
|
|
|
sync_info.setTotalFileNumber( m_total_files.toInt() );
|
|
|
|
}
|
|
|
|
|
|
|
|
rate = m_buffer.section( "/s ", 0, 0 ).section( " ", -1, -1 ).stripWhiteSpace();
|
|
|
|
|
|
|
|
if ( !rate.isEmpty() )
|
|
|
|
{
|
|
|
|
rate.append( "/s" );
|
|
|
|
rate.insert( rate.length() - 4, " " );
|
|
|
|
|
|
|
|
sync_info.setTransferRate( rate );
|
|
|
|
}
|
|
|
|
|
|
|
|
m_buffer = TQString();
|
|
|
|
}
|
|
|
|
else if ( !m_buffer[0].isSpace() && m_buffer.endsWith( "\n" ) && m_buffer.contains( "/s ", true ) == 0 )
|
|
|
|
{
|
|
|
|
sync_info.setText( m_buffer.stripWhiteSpace() );
|
|
|
|
|
|
|
|
if ( m_buffer.contains( "files to consider" ) != 0 )
|
|
|
|
{
|
|
|
|
m_total_files = m_buffer.section( " files to consider", 0, 0 ).section( " ", -1, -1 ).stripWhiteSpace();
|
|
|
|
|
|
|
|
sync_info.setTotalFileNumber( m_total_files.toInt() );
|
|
|
|
}
|
|
|
|
|
|
|
|
m_buffer = TQString();
|
|
|
|
}
|
|
|
|
|
|
|
|
emit progress( sync_info );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Smb4KSynchronizer::slotReceivedStderr( TDEProcess *, char *buf, int len )
|
|
|
|
{
|
|
|
|
TQString error_message = TQString::fromLocal8Bit( buf, len );
|
|
|
|
|
|
|
|
// At least under Debian unstable (20051216), rsync emits an error
|
|
|
|
// when you kill the process (using SIGTERM). Pressing the cancel
|
|
|
|
// button will exactly do this. Thus, we need to exclude this occasion
|
|
|
|
// from here.
|
|
|
|
if ( !cancel && error_message.contains( "rsync error:", true ) != 0 )
|
|
|
|
{
|
|
|
|
// Cancel the whole synchronization in case an error occurred.
|
|
|
|
// If we don't do it, the user might be flooded with error messages
|
|
|
|
// especially if you try to synchronize a local copy with a remote
|
|
|
|
// share that is mounted read-only.
|
|
|
|
abort();
|
|
|
|
Smb4KError::error( ERROR_SYNCHRONIZING, TQString(), error_message );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cancel = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Smb4KSynchronizer::slotShutdown()
|
|
|
|
{
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "smb4ksynchronizer.moc"
|