tools: MimeDump<> can have all static members
[barry.git] / src / restore.cc
blobd00b3cef0585470ba8860c44469263ece63a0c97
1 ///
2 /// \file restore.cc
3 /// Builder class for restoring from Barry Backup files
4 ///
6 /*
7 Copyright (C) 2010, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #include "restore.h"
23 #include "tarfile.h"
24 #include "error.h"
25 #include <sstream>
26 #include <iomanip>
27 #include <iostream>
28 #include <string.h>
30 namespace Barry {
32 namespace {
34 int CountFiles(reuse::TarFile &tar,
35 const Barry::Restore::DBListType &restoreList,
36 bool default_all_db)
38 int count = 0;
39 std::string name, last_name;
40 bool good = false;
42 while( tar.ReadNextFilenameOnly(name) ) {
43 std::string::size_type pos = name.rfind('/');
44 if( pos == std::string::npos )
45 continue; // bad name
46 std::string dbname = name.substr(0, pos);
48 if( dbname != last_name ) {
49 last_name = dbname;
50 good = (default_all_db && restoreList.size() == 0) ||
51 restoreList.IsSelected(dbname);
53 if( good )
54 count++;
56 return count;
61 //////////////////////////////////////////////////////////////////////////////
62 // Static Restore members
64 /// Splits a tarpath of the form "DBName/DBID" into separate string values.
65 /// Returns true if successful, false if tarpath is a bad name.
66 bool Restore::SplitTarPath(const std::string &tarpath,
67 std::string &dbname,
68 std::string &dbid_text,
69 uint8_t &dbrectype,
70 uint32_t &dbid)
72 std::string::size_type pos = tarpath.rfind('/');
73 if( pos == std::string::npos )
74 return false; // bad name
76 dbname = tarpath.substr(0, pos);
77 dbid_text = tarpath.substr(pos + 1);
78 if( dbname.size() == 0 || dbid_text.size() == 0 )
79 return false; // bad name
81 std::istringstream iss(dbid_text);
82 unsigned int temp;
83 iss >> std::hex >> dbid >> temp;
84 dbrectype = (uint8_t) temp;
86 return true;
90 //////////////////////////////////////////////////////////////////////////////
91 // Restore - constructors
93 Restore::Restore(const std::string &tarpath, bool default_all_db)
94 : m_default_all_db(default_all_db)
95 , m_end_of_tar(false)
96 , m_tar_record_loaded(false)
97 , m_rec_type(0)
98 , m_unique_id(0)
100 try {
101 m_tar.reset( new reuse::TarFile(tarpath.c_str(), false,
102 &reuse::gztar_ops_nonthread, true) );
104 catch( reuse::TarFile::TarError &te ) {
105 throw Barry::RestoreError(te.what());
109 Restore::~Restore()
114 //////////////////////////////////////////////////////////////////////////////
115 // Restore - Protected helpers
117 bool Restore::IsSelected(const std::string &dbName) const
119 // if nothing is in the list, default to all
120 if( m_dbList.size() == 0 )
121 return true;
122 else
123 return m_dbList.IsSelected(dbName);
127 //////////////////////////////////////////////////////////////////////////////
128 // Restore - Public API
130 void Restore::AddDB(const std::string &dbName)
132 m_dbList.push_back(dbName);
135 void Restore::SkipCurrentDB()
137 // skip all records until next DB
138 try {
139 while( Retrieve(m_record_data) ) {
140 std::cerr << "Skipping: "
141 << m_current_dbname << "/"
142 << m_tar_id_text << std::endl;
143 m_tar_record_loaded = false;
146 catch( reuse::TarFile::TarError & ) {
147 m_end_of_tar = true;
151 unsigned int Restore::GetRecordTotal(const std::string &tarpath) const
153 unsigned int count = 0;
155 std::auto_ptr<reuse::TarFile> tar;
157 try {
158 // do a scan through the tar file
159 tar.reset( new reuse::TarFile(tarpath.c_str(), false,
160 &reuse::gztar_ops_nonthread, true) );
161 count = CountFiles(*tar, m_dbList, m_default_all_db);
163 catch( reuse::TarFile::TarError &te ) {
164 throw Barry::RestoreError(te.what());
166 return count;
170 //////////////////////////////////////////////////////////////////////////////
171 // Barry::Builder overrides
173 bool Restore::Retrieve(Data &record_data)
175 if( m_end_of_tar )
176 return false;
178 // if loaded, we are likely on a database
179 // boundary, and the last read crossed it, so don't load again
180 if( m_tar_record_loaded )
181 return true;
183 // search for a valid record
184 for(;;) {
185 // load record data from tar file
186 std::string filename;
187 if( !m_tar->ReadNextFile(filename, record_data) ) {
188 // assume end of file
189 m_end_of_tar = true;
190 return false;
192 m_tar_record_loaded = true;
194 // split record filename into dbname and ID
195 std::string dbname;
196 if( !SplitTarPath(filename, dbname, m_tar_id_text, m_rec_type, m_unique_id) ) {
197 // invalid filename, skip it
198 std::cerr << "Skipping invalid tar record: " << filename << std::endl;
199 continue;
202 // are we working on the same dbname as last time?
203 // if so, go ahead!
204 if( m_current_dbname == dbname ) {
205 return true;
208 // DIFFERENT DBNAME from here on down!
210 // does the filter allow this record?
211 // if not, skip it and continue looking
212 if( !IsSelected(dbname) ) {
213 m_tar_record_loaded = false;
214 continue;
217 // all checks pass, load the new dbname, and return false
218 // if we are on a dbname boundary
219 bool r_val = false;
220 if( m_current_dbname.size() == 0 ) {
221 // this is the first time through Retrieve, so ok
222 r_val = true;
225 m_current_dbname = dbname;
226 return r_val;
230 bool Restore::BuildRecord(Barry::DBData &data,
231 size_t &offset,
232 const Barry::IConverter *ic)
234 if( !Retrieve(m_record_data) )
235 return false;
237 data.SetVersion(Barry::DBData::REC_VERSION_1);
238 data.SetDBName(m_current_dbname);
239 data.SetIds(m_rec_type, m_unique_id);
240 data.SetOffset(offset);
242 int packet_size = offset + m_record_data.GetSize();
243 unsigned char *buf = data.UseData().GetBuffer(packet_size);
244 memcpy(buf + offset, m_record_data.GetData(), m_record_data.GetSize());
245 offset += m_record_data.GetSize();
246 data.UseData().ReleaseBuffer(packet_size);
248 // clear loaded flag, as it has now been used
249 m_tar_record_loaded = false;
250 return true;
253 bool Restore::FetchRecord(Barry::DBData &data, const Barry::IConverter *ic)
255 if( !Retrieve(data.UseData()) )
256 return false;
258 data.SetVersion(Barry::DBData::REC_VERSION_1);
259 data.SetDBName(m_current_dbname);
260 data.SetIds(m_rec_type, m_unique_id);
261 data.SetOffset(0);
263 // clear loaded flag, as it has now been used
264 m_tar_record_loaded = false;
265 return true;
268 bool Restore::EndOfFile() const
270 return m_end_of_tar;
273 } // namespace Barry