diff --git a/chunk_index.cc b/chunk_index.cc index 5220004..aae457c 100644 --- a/chunk_index.cc +++ b/chunk_index.cc @@ -107,8 +107,8 @@ ChunkIndex::ChunkIndex( EncryptionKey const & key, TmpMgr & tmpMgr, { if ( !prohibitChunkIndexLoading ) loadIndex( *this ); - dPrintf( "Chunk index for %s is instantiated and initialized, hasKey: %s\n", - indexPath.c_str(), key.hasKey() ? "true" : "false" ); + dPrintf( "%s for %s is instantiated and initialized, hasKey: %s\n", + __CLASS, indexPath.c_str(), key.hasKey() ? "true" : "false" ); } Bundle::Id const * ChunkIndex::findChunk( ChunkId::RollingHashPart rollingHash, diff --git a/config.cc b/config.cc index 44afea3..c8ca48f 100644 --- a/config.cc +++ b/config.cc @@ -103,32 +103,35 @@ static struct Config::~Config() { // prevent memleak - if ( default_instance ) + if ( want_cleanup ) delete storable; } -Config::Config() +Config::Config(): + want_cleanup( true ) { ConfigInfo * configInfo = new ConfigInfo; - default_instance = true; storable = configInfo; - dPrintf( "Config is instantiated and initialized with default values\n" ); + dPrintf( "%s is instantiated and initialized with default values\n", + __CLASS ); } -Config::Config( ConfigInfo * configInfo ) +Config::Config( ConfigInfo * configInfo ): + want_cleanup( false ) { storable = configInfo; - default_instance = false; - dPrintf( "Config is instantiated and initialized with supplied ConfigInfo\n" ); + dPrintf( "%s is instantiated and initialized with supplied ConfigInfo\n", + __CLASS ); } -Config::Config( const Config & configIn, ConfigInfo * configInfo ) +Config::Config( const Config & configIn, ConfigInfo * configInfo ): + want_cleanup( false ) { configInfo->MergeFrom( *configIn.storable ); *this = configIn; storable = configInfo; - default_instance = false; - dPrintf( "Config is instantiated and initialized with supplied values\n" ); + dPrintf( "%s is instantiated and initialized with supplied values\n", + __CLASS ); } Config::OpCodes Config::parseToken( const char * option, const OptionType type ) @@ -150,7 +153,8 @@ Config::OpCodes Config::parseToken( const char * option, const OptionType type ) return Config::oBadOption; } -bool Config::parseOption( const char * option, const OptionType type ) +bool Config::parseOrValidate( const char * option, const OptionType type, + bool validate ) { string prefix; if ( type == Runtime ) @@ -158,7 +162,9 @@ bool Config::parseOption( const char * option, const OptionType type ) else if ( type == Storable ) prefix.assign( "storable" ); - dPrintf( "Parsing %s option \"%s\"...\n", prefix.c_str(), option ); + + dPrintf( "%s %s option \"%s\"...\n", ( validate ? "Validating" : "Parsing" ), + prefix.c_str(), option ); bool hasValue = false; size_t optionLength = strlen( option ); @@ -166,12 +172,11 @@ bool Config::parseOption( const char * option, const OptionType type ) if ( sscanf( option, "%[^=]=%s", optionName, optionValue ) == 2 ) { - dPrintf( "%s option name: %s, value: %s\n", prefix.c_str(), - optionName, optionValue ); + dPrintf( "%s option %s: %s\n", prefix.c_str(), optionName, optionValue ); hasValue = true; } else - dPrintf( "%s option name: %s\n", prefix.c_str(), option ); + dPrintf( "%s option %s\n", prefix.c_str(), option ); int opcode = parseToken( hasValue ? optionName : option, type ); @@ -391,17 +396,11 @@ bool Config::parseOption( const char * option, const OptionType type ) void Config::showHelp( const OptionType type ) { - string prefix; - if ( type == Runtime ) - prefix.assign( "runtime" ); - else - if ( type == Storable ) - prefix.assign( "storable" ); fprintf( stderr, "Available %s options overview:\n\n" "== help ==\n" -"shows this message\n" -"", prefix.c_str() ); +"show this message\n" +"", ( type == Runtime ? "runtime" : ( type == Storable ? "storable" : "" ) ) ); for ( u_int i = 0; ConfigHelper::keywords[ i ].name; i++ ) { @@ -415,7 +414,7 @@ void Config::showHelp( const OptionType type ) } } -bool Config::parse( const string & str, google::protobuf::Message * mutable_message ) +bool Config::parseProto( const string & str, google::protobuf::Message * mutable_message ) { return google::protobuf::TextFormat::ParseFromString( str, mutable_message ); } @@ -428,10 +427,59 @@ string Config::toString( google::protobuf::Message const & message ) return str; } -bool Config::validate( const string & configData, const string & newConfigData ) +bool Config::validateProto( const string & configData, const string & newConfigData ) { - ConfigInfo newConfig; - return parse( newConfigData, &newConfig ); + Config config; + dPrintf( "Validating proto...\n" ); + if ( !parseProto( newConfigData, config.storable ) ) + return false; + + const ::google::protobuf::Descriptor * configDescriptor = + config.storable->descriptor(); + for ( int i = 0; i < configDescriptor->field_count(); i++ ) + { + const ::google::protobuf::FieldDescriptor * storage = + configDescriptor->field( i ); + dPrintf( "Storage: %s - %d - %d\n", storage->name().c_str(), + storage->label(), storage->type()); + + // TODO: support for top-level fields + if ( storage->type() == ::google::protobuf::FieldDescriptor::TYPE_MESSAGE ) + { + const ::google::protobuf::Descriptor * storageDescriptor = + storage->message_type(); + + for ( int j = 0; j < storageDescriptor->field_count(); j++ ) + { + const ::google::protobuf::FieldDescriptor * field = + storageDescriptor->field( j ); + + dPrintf( "Field: %s - %d - %d\n", field->name().c_str(), + field->label(), field->type()); + + string option = storage->name() + "." + field->name(); + + if ( !config.parseOrValidate( option.c_str(), Storable, true ) ) + { + fprintf( stderr, "Invalid option specified: %s\n", + option.c_str() ); + return false; + } + } + } + } + + return true; +} + +void Config::reset_storable() +{ + // TODO: Use protobuf introspection + // to fill messages in loop with default values + // without explicit declaration + SET_STORABLE( chunk, max_size, GET_STORABLE( chunk, max_size ) ); + SET_STORABLE( bundle, max_payload_size, GET_STORABLE( bundle, max_payload_size ) ); + SET_STORABLE( bundle, compression_method, GET_STORABLE( bundle, compression_method ) ); } void Config::show() @@ -449,11 +497,11 @@ bool Config::editInteractively( ZBackupBase * zbb ) string configData( toString( *zbb->config.storable ) ); string newConfigData( configData ); - if ( !zbb->spawnEditor( newConfigData, &validate ) ) + if ( !zbb->spawnEditor( newConfigData, &validateProto ) ) return false; + ConfigInfo newConfig; - if ( !parse( newConfigData, &newConfig ) ) - return false; + parseProto( newConfigData, &newConfig ); if ( toString( *zbb->config.storable ) == toString( newConfig ) ) { verbosePrintf( "No changes made to config\n" ); @@ -461,8 +509,7 @@ bool Config::editInteractively( ZBackupBase * zbb ) } verbosePrintf( "Updating configuration...\n" ); - - zbb->config.storable->CopyFrom( newConfig ); + zbb->config.storable->MergeFrom( newConfig ); verbosePrintf( "Configuration successfully updated!\n" "Updated configuration:\n%s", toString( *zbb->config.storable ).c_str() ); diff --git a/config.hh b/config.hh index b7c9ffb..4a3ce39 100644 --- a/config.hh +++ b/config.hh @@ -11,6 +11,7 @@ #include "mt.hh" #include "backup_exchanger.hh" +// TODO: make *_storable to be variadic #define SET_STORABLE( storage, property, value ) (\ {\ dPrintf( "storable->mutable_"#storage"()->set_"#property"( "#value" )\n" ); \ @@ -64,14 +65,14 @@ public: oDeprecated, oUnsupported } OpCodes; - // Validator for user-supplied configuration - static bool validate( const string &, const string & ); + // Validator for user-supplied storable configuration + static bool validateProto( const string &, const string & ); - static bool parse( const string & str, google::protobuf::Message * mutable_message ); + static bool parseProto( const string &, google::protobuf::Message * ); static void showHelp( const OptionType ); - static string toString( google::protobuf::Message const & message ); + static string toString( google::protobuf::Message const & ); // Edit current configuration // returns true if configuration is changed @@ -81,18 +82,20 @@ public: static void show( const ConfigInfo & ); void show(); - OpCodes parseToken( const char * option, const OptionType ); - bool parseOption( const char * option, const OptionType ); + OpCodes parseToken( const char *, const OptionType ); + bool parseOrValidate( const char *, const OptionType, bool validate = false ); Config( const Config &, ConfigInfo * ); Config( ConfigInfo * ); Config(); ~Config(); + void reset_storable(); + RuntimeConfig runtime; ConfigInfo * storable; private: - bool default_instance; + bool want_cleanup; }; #include "zbackup_base.hh" diff --git a/debug.hh b/debug.hh index abfeb9a..5989d2d 100644 --- a/debug.hh +++ b/debug.hh @@ -5,9 +5,12 @@ #define DEBUG_HH_INCLUDED__ #include +#include // Macros we use to output debugging information +#define __CLASS typeid( *this ).name() + #ifndef NDEBUG #define __FILE_BASE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) @@ -20,6 +23,7 @@ #define UNW_LOCAL_ONLY #include +// TODO: pretty backtraces #define dPrintBacktrace( ... ) () #else #define dPrintBacktrace( ... ) () diff --git a/zbackup.cc b/zbackup.cc index 2f93a60..1afec24 100644 --- a/zbackup.cc +++ b/zbackup.cc @@ -355,23 +355,21 @@ int main( int argc, char *argv[] ) if ( strcmp( argv[ x ], "--exchange" ) == 0 && x + 1 < argc ) { fprintf( stderr, "%s is deprecated, use -O exchange instead\n", argv[ x ] ); - deprecated.assign( argv[ x ] + 2 ); - deprecated.append( "=" ); - deprecated.append( argv[ x + 1 ] ); + deprecated = argv[ x ] + 2;//; + "=" + argv[ x + 1 ]; + deprecated += "="; + deprecated += argv[ x + 1 ]; option = deprecated.c_str(); - if ( option ) - goto parse_option; + goto parse_option; } else if ( strcmp( argv[ x ], "--threads" ) == 0 && x + 1 < argc ) { fprintf( stderr, "%s is deprecated, use -O threads instead\n", argv[ x ] ); - deprecated.assign( argv[ x ] + 2 ); - deprecated.append( "=" ); - deprecated.append( argv[ x + 1 ] ); + deprecated = argv[ x ] + 2; + deprecated += "="; + deprecated += argv[ x + 1 ]; option = deprecated.c_str(); - if ( option ) - goto parse_option; + goto parse_option; } else if ( strcmp( argv[ x ], "--cache-size" ) == 0 && x + 1 < argc ) @@ -383,25 +381,21 @@ int main( int argc, char *argv[] ) if ( sscanf( argv[ x + 1 ], "%zu %15s %n", &cacheSizeMb, suffix, &n ) == 2 && !argv[ x + 1][ n ] ) - deprecated.assign( argv[ x ] + 2 ); - deprecated.append( "=" ); - deprecated.append( Utils::numberToString( cacheSizeMb ) ); - deprecated.append( "MiB" ); + deprecated = argv[ x ] + 2; + deprecated += "=" + Utils::numberToString( cacheSizeMb ) + "MiB"; option = deprecated.c_str(); - if ( option ) - goto parse_option; + goto parse_option; } else if ( strcmp( argv[ x ], "--compression" ) == 0 && x + 1 < argc ) { fprintf( stderr, "%s is deprecated, use -o bundle.compression_method instead\n", argv[ x ] ); - deprecated.assign( argv[ x ] + 2 ); - deprecated.append( "=" ); - deprecated.append( argv[ x + 1 ] ); + deprecated = argv[ x ] + 2; + deprecated += "="; + deprecated += argv[ x + 1 ]; option = deprecated.c_str(); optionType = Config::Storable; - if ( option ) - goto parse_option; + goto parse_option; } else if ( strcmp( argv[ x ], "--help" ) == 0 || strcmp( argv[ x ], "-h" ) == 0 ) @@ -429,7 +423,7 @@ int main( int argc, char *argv[] ) else { parse_option: - if ( !config.parseOption( option, optionType ) ) + if ( !config.parseOrValidate( option, optionType ) ) goto invalid_option; } } diff --git a/zbackup_base.cc b/zbackup_base.cc index 8aed669..0a1c693 100644 --- a/zbackup_base.cc +++ b/zbackup_base.cc @@ -67,7 +67,7 @@ ZBackupBase::ZBackupBase( string const & storageDir, string const & password ): config( extendedStorageInfo.mutable_config() ) { propagateUpdate(); - dPrintf("ZBackupBase for %s is instantiated and initialized\n", + dPrintf("%s for %s is instantiated and initialized\n", __CLASS, storageDir.c_str() ); } @@ -82,7 +82,7 @@ ZBackupBase::ZBackupBase( string const & storageDir, string const & password, config( configIn, extendedStorageInfo.mutable_config() ) { propagateUpdate(); - dPrintf("ZBackupBase for %s is instantiated and initialized\n", + dPrintf("%s for %s is instantiated and initialized\n", __CLASS, storageDir.c_str() ); } @@ -97,7 +97,7 @@ ZBackupBase::ZBackupBase( string const & storageDir, string const & password, config( extendedStorageInfo.mutable_config() ) { propagateUpdate(); - dPrintf("ZBackupBase for %s is instantiated and initialized\n", + dPrintf("%s for %s is instantiated and initialized\n", __CLASS, storageDir.c_str() ); } @@ -112,7 +112,7 @@ ZBackupBase::ZBackupBase( string const & storageDir, string const & password, config( configIn, extendedStorageInfo.mutable_config() ) { propagateUpdate(); - dPrintf("ZBackupBase for %s is instantiated and initialized\n", + dPrintf("%s for %s is instantiated and initialized\n", __CLASS, storageDir.c_str() ); } @@ -153,14 +153,8 @@ void ZBackupBase::initStorage( string const & storageDir, { StorageInfo storageInfo; ExtendedStorageInfo extendedStorageInfo; - - ConfigInfo * storable = extendedStorageInfo.mutable_config(); - // TODO: Use protobuf reflection in loop - // to fill messages with default values - // without explicitly defining them - SET_STORABLE( chunk, max_size, GET_STORABLE( chunk, max_size ) ); - SET_STORABLE( bundle, max_payload_size, GET_STORABLE( bundle, max_payload_size ) ); - SET_STORABLE( bundle, compression_method, GET_STORABLE( bundle, compression_method ) ); + Config config( extendedStorageInfo.mutable_config() ); + config.reset_storable(); EncryptionKey encryptionkey = EncryptionKey::noKey();