00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "restore.h"
00023 #include "tarfile.h"
00024 #include "error.h"
00025 #include <sstream>
00026 #include <iomanip>
00027 #include <iostream>
00028 #include <string.h>
00029 #include <algorithm>
00030
00031 using namespace std;
00032
00033 namespace Barry {
00034
00035 namespace {
00036
00037 int CountFiles(reuse::TarFile &tar,
00038 const Barry::Restore::DBListType &restoreList,
00039 Barry::Restore::DBListType *available,
00040 bool default_all_db)
00041 {
00042 int count = 0;
00043 std::string name, last_name;
00044 bool good = false;
00045
00046 while( tar.ReadNextFilenameOnly(name) ) {
00047 std::string::size_type pos = name.rfind('/');
00048 if( pos == std::string::npos )
00049 continue;
00050 std::string dbname = name.substr(0, pos);
00051
00052 if( dbname != last_name ) {
00053 last_name = dbname;
00054 good = (default_all_db && restoreList.size() == 0) ||
00055 restoreList.IsSelected(dbname);
00056
00057 if( good && available )
00058 available->push_back(dbname);
00059 }
00060 if( good )
00061 count++;
00062 }
00063 return count;
00064 }
00065
00066 }
00067
00068
00069
00070
00071
00072
00073 bool Restore::SplitTarPath(const std::string &tarpath,
00074 std::string &dbname,
00075 std::string &dbid_text,
00076 uint8_t &dbrectype,
00077 uint32_t &dbid)
00078 {
00079 std::string::size_type pos = tarpath.rfind('/');
00080 if( pos == std::string::npos )
00081 return false;
00082
00083 dbname = tarpath.substr(0, pos);
00084 dbid_text = tarpath.substr(pos + 1);
00085 if( dbname.size() == 0 || dbid_text.size() == 0 )
00086 return false;
00087
00088 std::istringstream iss(dbid_text);
00089 unsigned int temp;
00090 iss >> std::hex >> dbid >> temp;
00091 dbrectype = (uint8_t) temp;
00092
00093 return true;
00094 }
00095
00096
00097
00098
00099
00100 Restore::Restore(const std::string &tarpath, bool default_all_db)
00101 : m_tarpath(tarpath)
00102 , m_default_all_db(default_all_db)
00103 , m_tar_record_state(RS_EMPTY)
00104 , m_rec_type(0)
00105 , m_unique_id(0)
00106 {
00107 try {
00108 m_tar.reset( new reuse::TarFile(tarpath.c_str(), false,
00109 &reuse::gztar_ops_nonthread, true) );
00110 }
00111 catch( reuse::TarFile::TarError &te ) {
00112 throw Barry::RestoreError(te.what());
00113 }
00114 }
00115
00116 Restore::~Restore()
00117 {
00118 }
00119
00120
00121
00122
00123
00124 bool Restore::IsSelected(const std::string &dbName) const
00125 {
00126
00127
00128
00129 if( m_dbSkipList.IsSelected(dbName) )
00130 return false;
00131 else if( m_dbList.size() == 0 )
00132 return m_default_all_db;
00133 else
00134 return m_dbList.IsSelected(dbName);
00135 }
00136
00137
00138
00139
00140
00141 void Restore::AddDB(const std::string &dbName)
00142 {
00143 if( find(m_dbList.begin(), m_dbList.end(), dbName) == m_dbList.end() ) {
00144
00145 m_dbList.push_back(dbName);
00146 }
00147 }
00148
00149 void Restore::Add(const DBListType &dbList)
00150 {
00151 for( DBListType::const_iterator i = dbList.begin();
00152 i != dbList.end();
00153 ++i )
00154 {
00155 AddDB(*i);
00156 }
00157 }
00158
00159 void Restore::Add(const DatabaseDatabase &dbdb)
00160 {
00161 for( DatabaseDatabase::DatabaseArrayType::const_iterator i = dbdb.Databases.begin();
00162 i != dbdb.Databases.end();
00163 ++i )
00164 {
00165 AddDB(i->Name);
00166 }
00167 }
00168
00169 void Restore::AddSkipDB(const std::string &dbName)
00170 {
00171 if( find(m_dbSkipList.begin(), m_dbSkipList.end(), dbName) == m_dbSkipList.end() ) {
00172
00173 m_dbSkipList.push_back(dbName);
00174 }
00175 }
00176
00177 void Restore::SkipCurrentDB()
00178 {
00179
00180 try {
00181 Restore::RetrievalState state;
00182 while( (state = Retrieve(m_record_data)) == RS_NEXT ) {
00183 std::cerr << "Skipping: "
00184 << m_current_dbname << "/"
00185 << m_tar_id_text << std::endl;
00186 m_tar_record_state = RS_EMPTY;
00187 }
00188
00189 if( state == RS_DBEND ) {
00190
00191
00192 m_tar_record_state = RS_NEXT;
00193 }
00194 }
00195 catch( reuse::TarFile::TarError & ) {
00196 m_tar_record_state = RS_EOF;
00197 }
00198 }
00199
00200 unsigned int Restore::GetRecordTotal() const
00201 {
00202 return GetRecordTotal(m_tarpath, m_dbList, m_default_all_db);
00203 }
00204
00205 unsigned int Restore::GetRecordTotal(const std::string &tarpath,
00206 const DBListType &dbList,
00207 bool default_all_db)
00208 {
00209 unsigned int count = 0;
00210
00211 std::auto_ptr<reuse::TarFile> tar;
00212
00213 try {
00214
00215 tar.reset( new reuse::TarFile(tarpath.c_str(), false,
00216 &reuse::gztar_ops_nonthread, true) );
00217 count = CountFiles(*tar, dbList, 0, default_all_db);
00218 }
00219 catch( reuse::TarFile::TarError &te ) {
00220 throw Barry::RestoreError(te.what());
00221 }
00222 return count;
00223 }
00224
00225 Barry::Restore::DBListType Restore::GetDBList() const
00226 {
00227 return GetDBList(m_tarpath);
00228 }
00229
00230 Barry::Restore::DBListType Restore::GetDBList(const std::string &tarpath)
00231 {
00232 std::auto_ptr<reuse::TarFile> tar;
00233 DBListType available, empty;
00234
00235 try {
00236
00237 tar.reset( new reuse::TarFile(tarpath.c_str(), false,
00238 &reuse::gztar_ops_nonthread, true) );
00239 CountFiles(*tar, empty, &available, true);
00240 return available;
00241 }
00242 catch( reuse::TarFile::TarError &te ) {
00243 throw Barry::RestoreError(te.what());
00244 }
00245 }
00246
00247 bool Restore::GetNextMeta(DBData &data)
00248 {
00249
00250
00251
00252 if( m_tar_record_state == RS_EMPTY ) {
00253 Retrieve(m_record_data);
00254 }
00255
00256
00257
00258
00259 switch( m_tar_record_state )
00260 {
00261 case RS_NEXT:
00262 data.SetVersion(Barry::DBData::REC_VERSION_1);
00263 data.SetDBName(m_current_dbname);
00264 data.SetIds(m_rec_type, m_unique_id);
00265 data.SetOffset(0);
00266 return true;
00267
00268 default:
00269 return false;
00270 }
00271 }
00272
00273
00274
00275
00276
00277 Restore::RetrievalState Restore::Retrieve(Data &record_data)
00278 {
00279
00280 if( m_tar_record_state != RS_EMPTY )
00281 return m_tar_record_state;
00282
00283
00284 for(;;) {
00285
00286 std::string filename;
00287 if( !m_tar->ReadNextFile(filename, record_data) ) {
00288
00289 return m_tar_record_state = RS_EOF;
00290 }
00291 m_tar_record_state = RS_UNKNOWN;
00292
00293
00294 std::string dbname;
00295 if( !SplitTarPath(filename, dbname, m_tar_id_text, m_rec_type, m_unique_id) ) {
00296
00297 std::cerr << "Skipping invalid tar record: " << filename << std::endl;
00298 continue;
00299 }
00300
00301
00302
00303 if( m_current_dbname == dbname ) {
00304 return m_tar_record_state = RS_NEXT;
00305 }
00306
00307
00308 m_tar_record_state = RS_DBEND;
00309
00310
00311
00312 if( !IsSelected(dbname) ) {
00313 continue;
00314 }
00315
00316
00317
00318 if( m_current_dbname.size() == 0 ) {
00319
00320 m_tar_record_state = RS_NEXT;
00321 }
00322
00323 m_current_dbname = dbname;
00324 return m_tar_record_state;
00325 }
00326 }
00327
00328 bool Restore::BuildRecord(Barry::DBData &data,
00329 size_t &offset,
00330 const Barry::IConverter *ic)
00331 {
00332
00333
00334 switch( Retrieve(m_record_data) )
00335 {
00336 case RS_NEXT:
00337 {
00338 data.SetVersion(Barry::DBData::REC_VERSION_1);
00339 data.SetDBName(m_current_dbname);
00340 data.SetIds(m_rec_type, m_unique_id);
00341 data.SetOffset(offset);
00342
00343 int packet_size = offset + m_record_data.GetSize();
00344 unsigned char *buf = data.UseData().GetBuffer(packet_size);
00345 memcpy(buf + offset, m_record_data.GetData(), m_record_data.GetSize());
00346 offset += m_record_data.GetSize();
00347 data.UseData().ReleaseBuffer(packet_size);
00348
00349
00350 m_tar_record_state = RS_EMPTY;
00351 return true;
00352 }
00353
00354 case RS_EMPTY:
00355 case RS_UNKNOWN:
00356 default:
00357 throw std::logic_error("Invalid state in Restore::BuildRecord()");
00358
00359 case RS_DBEND:
00360
00361
00362 m_tar_record_state = RS_NEXT;
00363 return false;
00364
00365 case RS_EOF:
00366
00367 return false;
00368 }
00369 }
00370
00371 bool Restore::FetchRecord(Barry::DBData &data, const Barry::IConverter *ic)
00372 {
00373
00374
00375
00376
00377
00378
00379
00380 if( m_tar_record_state == RS_EMPTY ) {
00381
00382
00383
00384 if( Retrieve(data.UseData()) == RS_DBEND ) {
00385 m_record_data = data.GetData();
00386 m_tar_record_state = RS_NEXT;
00387 return false;
00388 }
00389 }
00390 else {
00391 data.UseData() = m_record_data;
00392 }
00393
00394 switch( m_tar_record_state )
00395 {
00396 case RS_NEXT:
00397 data.SetVersion(Barry::DBData::REC_VERSION_1);
00398 data.SetDBName(m_current_dbname);
00399 data.SetIds(m_rec_type, m_unique_id);
00400 data.SetOffset(0);
00401
00402
00403 m_tar_record_state = RS_EMPTY;
00404 return true;
00405
00406 case RS_EMPTY:
00407 case RS_UNKNOWN:
00408 default:
00409 throw std::logic_error("Invalid state in Restore::FetchRecord()");
00410
00411 case RS_DBEND:
00412
00413
00414 m_tar_record_state = RS_NEXT;
00415 return false;
00416
00417 case RS_EOF:
00418
00419 return false;
00420 }
00421 }
00422
00423 bool Restore::EndOfFile() const
00424 {
00425 return m_tar_record_state == RS_EOF;
00426 }
00427
00428 }
00429