You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
389 lines
12 KiB
389 lines
12 KiB
/* This file is part of the Keep project
|
|
Copyright (C) 2006 Jean-Rémy Falleri <jr.falleri@laposte.net>
|
|
|
|
Keep 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.
|
|
|
|
Keep 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 Keep; if not, write to the
|
|
Free Software Foundation, Inc.,
|
|
51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. */
|
|
|
|
#include "rdbmanager.h"
|
|
|
|
#include <kprocess.h>
|
|
#include <kdebug.h>
|
|
#include <tqfile.h>
|
|
#include <keepsettings.h>
|
|
|
|
RDBManager::RDBManager()
|
|
{
|
|
}
|
|
|
|
RDBManager::~RDBManager()
|
|
{
|
|
}
|
|
|
|
void RDBManager::slotCheckBackup()
|
|
{
|
|
TQValueList<Backup> backups = outdatedBackupList();
|
|
TQValueList<Backup>::iterator it;
|
|
for ( it = backups.begin(); it != backups.end(); ++it )
|
|
{
|
|
doBackup(*it);
|
|
}
|
|
}
|
|
|
|
void RDBManager::slotForceBackup(TQValueList<Backup> backupList)
|
|
{
|
|
TQValueList<Backup>::iterator it;
|
|
for ( it = backupList.begin(); it != backupList.end(); ++it )
|
|
{
|
|
doBackup(*it);
|
|
}
|
|
}
|
|
|
|
TQString RDBManager::compareAtTime(Backup backup, TQDateTime date)
|
|
{
|
|
// Gets the rdiff-backup process
|
|
TDEProcess *proc = RDBProcess();
|
|
// Adds the options
|
|
*proc << "--compare-at-time";
|
|
*proc << TQString::number(date.toTime_t()); // increment date
|
|
// Adds source and dest
|
|
*proc << TQString(TQFile::encodeName(TDEProcess::quote(backup.source())));
|
|
*proc << TQString(TQFile::encodeName(TDEProcess::quote(backup.dest())));
|
|
// Adds the listener
|
|
RDBListener *listen = new RDBListener();
|
|
connect(proc,TQT_SIGNAL(receivedStdout(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdOut(TDEProcess *,char *,int)));
|
|
// Starts the process
|
|
if ( !proc->start(TDEProcess::Block, TDEProcess::AllOutput) )
|
|
kdDebug() << "Error starting rdiff-backup" << endl;
|
|
|
|
TQStringList output = listen->stdOut();
|
|
TQStringList::iterator it = output.begin();
|
|
|
|
kdDebug() << "Executed process: " << proc->args() << endl;
|
|
|
|
delete listen;
|
|
delete proc;
|
|
|
|
return (*it);
|
|
}
|
|
|
|
TQString RDBManager::listChangedSince(Backup backup, TQDateTime date)
|
|
{
|
|
// Gets the rdiff-backup process
|
|
TDEProcess *proc = RDBProcess();
|
|
// Adds the options
|
|
*proc << "--list-changed-since";
|
|
*proc << TQString::number(date.toTime_t()); // increment date
|
|
// Adds the dest
|
|
*proc << TQString(TQFile::encodeName(TDEProcess::quote(backup.dest())));
|
|
// Adds a listener
|
|
RDBListener *listen = new RDBListener();
|
|
connect(proc,TQT_SIGNAL(receivedStdout(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdOut(TDEProcess *,char *,int)));
|
|
// Starts the process
|
|
if ( !proc->start(TDEProcess::Block, TDEProcess::AllOutput) )
|
|
kdDebug() << "Error starting rdiff-backup" << endl;
|
|
|
|
TQStringList output = listen->stdOut();
|
|
TQStringList::iterator it = output.begin();
|
|
|
|
kdDebug() << "Executed process: " << proc->args() << endl;
|
|
|
|
delete listen;
|
|
delete proc;
|
|
|
|
return (*it);
|
|
}
|
|
|
|
TQString RDBManager::listAtTime(Backup backup, TQDateTime date)
|
|
{
|
|
// Gets the rdiff-backup process
|
|
TDEProcess *proc = RDBProcess();
|
|
// Adds the options
|
|
*proc << "--list-at-time";
|
|
*proc << TQString::number(date.toTime_t()); // increment date
|
|
// Adds the dest
|
|
*proc << TQString(TQFile::encodeName(TDEProcess::quote(backup.dest())));
|
|
// Adds a listener
|
|
RDBListener *listen = new RDBListener();
|
|
connect(proc,TQT_SIGNAL(receivedStdout(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdOut(TDEProcess *,char *,int)));
|
|
// Starts the process
|
|
if ( !proc->start(TDEProcess::Block, TDEProcess::AllOutput) )
|
|
kdDebug() << "Error starting rdiff-backup" << endl;
|
|
|
|
TQStringList output = listen->stdOut();
|
|
TQStringList::iterator it = output.begin();
|
|
|
|
kdDebug() << "Executed process: " << proc->args() << endl;
|
|
|
|
delete listen;
|
|
delete proc;
|
|
|
|
return (*it);
|
|
}
|
|
|
|
TQValueList<TQDateTime> RDBManager::incrementList(Backup backup)
|
|
{
|
|
// Gets the rdiff-backup process
|
|
TDEProcess *proc = RDBProcess();
|
|
// Adds the options
|
|
*proc << "--list-increments";
|
|
*proc << "-v2";
|
|
*proc << "--parsable-output";
|
|
// Adds the dest
|
|
*proc << TQString(TQFile::encodeName(TDEProcess::quote(backup.dest())));
|
|
// Adds a listener
|
|
RDBListener *listen = new RDBListener();
|
|
connect(proc,TQT_SIGNAL(receivedStdout(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdOut(TDEProcess *,char *,int)));
|
|
// Starts the process
|
|
if ( !proc->start(TDEProcess::Block, TDEProcess::AllOutput) )
|
|
kdDebug() << "Error starting rdiff-backup" << endl;
|
|
|
|
TQStringList output = listen->stdOut();
|
|
TQStringList::iterator it = output.begin();
|
|
|
|
TQStringList lines = TQStringList::split("\n",*it);
|
|
TQValueList<TQDateTime> dateList;
|
|
|
|
TQStringList::iterator it2 = output.begin();
|
|
for ( it2 = lines.begin(); it2 != lines.end(); ++it2 )
|
|
{
|
|
TQStringList field = TQStringList::split(" ",*it2);
|
|
TQStringList::iterator dateStr = field.begin();
|
|
long timestamp = (*dateStr).toUInt();
|
|
TQDateTime datetime;
|
|
datetime.setTime_t(timestamp);
|
|
dateList.append(datetime);
|
|
}
|
|
|
|
kdDebug() << "Executed process: " << proc->args() << endl;
|
|
|
|
delete listen;
|
|
delete proc;
|
|
|
|
return dateList;
|
|
}
|
|
|
|
TQDateTime RDBManager::lastIncrement(Backup backup)
|
|
{
|
|
TQValueList<TQDateTime> increments = incrementList(backup);
|
|
TQDateTime last = increments.last();
|
|
return last;
|
|
}
|
|
|
|
TQValueList<Backup> RDBManager::outdatedBackupList()
|
|
{
|
|
BackupConfig config;
|
|
TQValueList<Backup> backups = config.backupList();
|
|
TQValueList<Backup> outdated;
|
|
TQValueList<Backup>::iterator it;
|
|
kdDebug() << "Detecting outdated backup." << endl;
|
|
for ( it = backups.begin(); it != backups.end(); ++it )
|
|
{
|
|
TQDateTime last = lastIncrement(*it);
|
|
TQDate today = TQDate::currentDate();
|
|
if ( last.date().daysTo(today) >= (*it).interval() )
|
|
{
|
|
kdDebug() << "Detected outdated backup: " << (*it).source() << endl;
|
|
outdated.append(*it);
|
|
}
|
|
}
|
|
return outdated;
|
|
}
|
|
|
|
void RDBManager::slotRestoreBackup(Backup backup,TQDateTime time)
|
|
{
|
|
// Gets the rdiff-backup process
|
|
TDEProcess *proc = RDBProcess();
|
|
// Adds the options
|
|
*proc << "--force";
|
|
*proc << "--restore-as-of";
|
|
*proc << TQString::number(time.toTime_t()); // Date of the increment to restore
|
|
// Adds source and dest
|
|
*proc << TQString(TQFile::encodeName(TDEProcess::quote(backup.dest())));
|
|
*proc << TQString(TQFile::encodeName(TDEProcess::quote(backup.source())));
|
|
// Adds a listener (for output recording)
|
|
RDBListener *listen = new RDBListener();
|
|
connect(proc,TQT_SIGNAL(receivedStdout(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdOut(TDEProcess *,char *,int)));
|
|
connect(proc,TQT_SIGNAL(receivedStderr(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdErr(TDEProcess *,char *,int)));
|
|
// Starts the process
|
|
if ( !proc->start(TDEProcess::Block, TDEProcess::AllOutput) )
|
|
kdDebug() << "Error starting rdiff-backup" << endl;
|
|
|
|
kdDebug() << "Executed process: " << proc->args() << endl;
|
|
|
|
if ( !listen->isOk() )
|
|
{
|
|
kdDebug() << "Error message: " << listen->errorMessage() << endl;
|
|
emit backupError(backup,listen->errorMessage());
|
|
}
|
|
|
|
delete listen;
|
|
delete proc;
|
|
}
|
|
|
|
bool RDBManager::isRDB()
|
|
{
|
|
// Gets the rdiff-backup process
|
|
TDEProcess *proc = RDBProcess();
|
|
*proc << "-V";
|
|
// Adds a listener (for output recording)
|
|
RDBListener *listen = new RDBListener();
|
|
connect(proc,TQT_SIGNAL(receivedStdout(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdOut(TDEProcess *,char *,int)));
|
|
// Starts the process
|
|
if ( !proc->start(TDEProcess::Block, TDEProcess::AllOutput) )
|
|
kdDebug() << "Error starting rdiff-backup" << endl;
|
|
|
|
TQStringList outList = listen->stdOut();
|
|
TQStringList::iterator out = outList.begin();
|
|
|
|
kdDebug() << "Executed process: " << proc->args() << endl;
|
|
|
|
delete listen;
|
|
delete proc;
|
|
|
|
if ( *out == "" )
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
TQString RDBManager::RDBVersion()
|
|
{
|
|
// Gets the rdiff-backup process
|
|
TDEProcess *proc = RDBProcess();
|
|
*proc << "-V";
|
|
// Adds a listener (for output recording)
|
|
RDBListener *listen = new RDBListener();
|
|
connect(proc,TQT_SIGNAL(receivedStdout(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdOut(TDEProcess *,char *,int)));
|
|
// Starts the process
|
|
if ( !proc->start(TDEProcess::Block, TDEProcess::AllOutput) )
|
|
kdDebug() << "Error starting rdiff-backup" << endl;
|
|
|
|
TQStringList outList = listen->stdOut();
|
|
TQStringList::iterator out = outList.begin();
|
|
|
|
kdDebug() << "Executed process: " << proc->args() << endl;
|
|
|
|
delete listen;
|
|
delete proc;
|
|
|
|
return (*out).mid(13,5);
|
|
}
|
|
|
|
void RDBManager::doBackup(Backup backup)
|
|
{
|
|
// Gets the rdiff-backup process
|
|
TDEProcess *proc = RDBProcess(KeepSettings::controlRDBPriority,KeepSettings::rDBPriority());
|
|
// Adds include and exclude
|
|
if ( backup.useIncludeExclude() )
|
|
{
|
|
TQStringList includeExcludeList = backup.includeExcludeList();
|
|
TQStringList::iterator it;
|
|
for ( it = includeExcludeList.begin(); it != includeExcludeList.end(); ++it )
|
|
{
|
|
TQString type = (*it).left(1);
|
|
TQString file = (*it).right((*it).length() - 1);
|
|
if ( type == "I" )
|
|
{
|
|
*proc << "--include";
|
|
*proc << TQString(TQFile::encodeName(TDEProcess::quote(file)));
|
|
}
|
|
else if ( type == "E" )
|
|
{
|
|
*proc << "--exclude";
|
|
*proc << TQString(TQFile::encodeName(TDEProcess::quote(file)));
|
|
}
|
|
}
|
|
}
|
|
// Adds the option
|
|
// For simple mode
|
|
if ( !backup.useAdvancedConfig() )
|
|
{
|
|
if ( !backup.useCompression() )
|
|
*proc << "--no-compression";
|
|
|
|
if ( backup.excludeSpecialFiles() )
|
|
*proc << "--exclude-special-files";
|
|
}
|
|
// For advanced mode
|
|
else
|
|
{
|
|
TQStringList optionList = backup.optionList();
|
|
for ( TQStringList::Iterator it = optionList.begin(); it != optionList.end(); ++it )
|
|
{
|
|
*proc << *it;
|
|
}
|
|
}
|
|
// Adds source and dest
|
|
*proc << TQString(TQFile::encodeName(TDEProcess::quote(backup.source())));
|
|
*proc << TQString(TQFile::encodeName(TDEProcess::quote(backup.dest())));
|
|
// Adds a listener (for output recording)
|
|
RDBListener *listen = new RDBListener();
|
|
connect(proc,TQT_SIGNAL(receivedStdout(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdOut(TDEProcess *,char *,int)));
|
|
connect(proc,TQT_SIGNAL(receivedStderr(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdErr(TDEProcess *,char *,int)));
|
|
// Starts the process
|
|
if ( !proc->start(TDEProcess::Block, TDEProcess::AllOutput) )
|
|
kdDebug() << "Error starting rdiff-backup" << endl;
|
|
|
|
kdDebug() << "Executed process: " << proc->args() << endl;
|
|
kdDebug() << "Process status: " << listen->isOk() << endl;
|
|
|
|
if ( !listen->isOk() )
|
|
{
|
|
kdDebug() << "Error message: " << listen->errorMessage() << endl;
|
|
emit backupError(backup,listen->errorMessage());
|
|
}
|
|
else
|
|
emit backupSuccess(backup);
|
|
|
|
delete listen;
|
|
delete proc;
|
|
|
|
if ( !backup.neverDelete() )
|
|
{
|
|
removeOldIncrements(backup);
|
|
}
|
|
}
|
|
|
|
void RDBManager::removeOldIncrements(Backup backup)
|
|
{
|
|
// Gets the rdiff-backup process
|
|
TDEProcess *proc = RDBProcess();
|
|
// Adds the options
|
|
*proc << "--remove-older-than" << TQString("%1").arg(backup.deleteAfter()) + "D";
|
|
// Adds dest
|
|
*proc << backup.dest();
|
|
// Starts the process
|
|
if ( !proc->start(TDEProcess::Block, TDEProcess::AllOutput) )
|
|
kdDebug() << "Error starting rdiff-backup" << endl;
|
|
|
|
kdDebug() << "Executed process: " << proc->args() << endl;
|
|
|
|
delete proc;
|
|
}
|
|
|
|
TDEProcess *RDBManager::RDBProcess(bool isNice,int niceLevel)
|
|
{
|
|
TDEProcess *proc = new TDEProcess();
|
|
proc->setUseShell(true);
|
|
if ( isNice )
|
|
{
|
|
*proc << "nice" << "-n" << TQString("%1").arg(niceLevel);
|
|
}
|
|
*proc << "rdiff-backup";
|
|
|
|
return proc;
|
|
}
|
|
|
|
#include "rdbmanager.moc"
|