8 #include "filedata.hpp"
12 unsigned long long current_time() {
13 unsigned long long rc = 0;
14 time_t now_tt = time( 0 );
15 tm *now = localtime( &now_tt );
16 rc += ( now->tm_year + 1900ULL ) * 10000000000ULL;
17 rc += ( now->tm_mon + 1ULL ) * 100000000ULL;
18 rc += now->tm_mday * 1000000ULL;
19 rc += now->tm_hour * 10000ULL;
20 rc += now->tm_min * 100ULL;
26 template<class I, class O>
27 bool copy_until_full( I begin, I end, O out, unsigned long long &space ) {
28 const unsigned long long block_size = 0x200ULL;
32 while( 0 != space && i != end ) {
33 unsigned long long size = (*i)->getFileSize();
34 unsigned long long blocks = size & ( ~(block_size-1) );
35 if( blocks < size ) blocks += block_size;
37 if( blocks <= space ) {
42 // We missed a file that should be included so the backup is not complete
51 void populate_set( istream &in, SET &files ) {
53 FileData *data = new FileData();
55 if( data->getFileName().size() ) {
60 } while( ! in.eof() );
64 void partition_sets( const SET ¤t, const SET &old,
65 SET &added, SET &common, SET &old_common, SET &deleted ) {
68 set_difference( current.begin(), current.end(),
69 old.begin(), old.end(),
70 inserter( added, added.begin() ),
73 set_difference( old.begin(), old.end(),
74 current.begin(), current.end(),
75 inserter( deleted, deleted.begin() ),
78 set_union( current.begin(), current.end(),
79 old.begin(), old.end(),
80 inserter( common, common.begin() ),
83 set_union( old.begin(), old.end(),
84 common.begin(), common.end(),
85 inserter( old_common, old_common.begin() ),
90 // Parse the list of current files on stdin
92 populate_set( cin, current );
95 ifstream db( "test.db" );
96 if( db && db.good() ) {
97 populate_set( db, backed_up );
100 // Now divide the two sets into three sets (added, deleted and common )
101 file_set added, deleted, common, old_common;
102 partition_sets( current, backed_up, added, common, old_common, deleted );
104 // Now find the list of files to backup.
107 // backup all added files
108 copy( added.begin(), added.end(), inserter( backups, backups.begin() ) );
110 // Backup files that have been modified
111 file_set::iterator i = common.begin(), j = old_common.begin();
112 for( ; i != common.end(); ++i, ++j ) {
113 (*i)->setLastBackupDate( (*j)->getLastBackupDate() );
115 if( needs_backup( *j, *i ) ) backups.insert( *i );
118 // Now, sort the backups by filesize and build a list that'll fit on a DVD
119 file_vector backups_s;
120 copy( backups.begin(), backups.end(), back_inserter( backups_s ) );
122 FileDataSizeCmp sizecmp;
123 sort( backups_s.begin(), backups_s.end(), sizecmp );
126 unsigned long long space = 0x107c00000ULL; // 4220 MBytes
128 insert_iterator<file_set> final_i( final, final.begin() );
130 // Copy files over until full or out of files
131 bool complete = copy_until_full( backups_s.rbegin(),
136 // Now, sort the non-backed-up list by last_backup_date and back-fill
138 file_vector leftovers;
140 set_difference( current.begin(), current.end(),
141 final.begin(), final.end(),
142 back_inserter( leftovers ),
145 FileDataLastBackupCmp lastbackupcmp;
146 sort( leftovers.begin(), leftovers.end(), lastbackupcmp );
148 copy_until_full( leftovers.begin(), leftovers.end(), final_i, space );
151 unsigned long long now = current_time();
152 for( file_set::iterator k = final.begin(); k != final.end(); ++k ) {
153 (*k)->setLastBackupDate( now );
156 // Write the 'current' list to the dbfile
157 ofstream dbout( "test.db" );
158 copy( current.begin(), current.end(), ostream_iterator<FileData*>( dbout, "" ) );
160 // Write the 'final' list to stdout
161 copy( final.begin(), final.end(), ostream_iterator<FileData*>( cout, "" ) );
163 if( ! complete ) { cerr << "incomplete" << endl; }
166 for( file_set::iterator i = backed_up.begin(); i != backed_up.end(); ++i ) { delete *i; }
167 for( file_set::iterator i = current.begin(); i != current.end(); ++i ) { delete *i; }