Ejemplo n.º 1
0
// This mfunction creates 'numPlayers' player entries
// with username and password 'bot_X'.
bool CdbInterface::createTestPlayers(int numPlayers)
{
    bool rc = true;

    for (int i = 0; i < numPlayers; i++)
    {
        char buf[17];
        sprintf(buf, "bot_%i", i + 1);

        // First check that the player is not already there!
        char query[MAXQUERYSIZE];
        sprintf(query, "SELECT username FROM pokeruser where username='******';",
                buf);

        if (!dbase_->dbQuery(query))
        {
            Sys_LogError("Query to create test player failed(0).");
            return false;
        }

        const char* fetched = dbase_->dbFetchRow();
        if (fetched == NULL)
        {   // Okay now create the player
            MD5 context;
            context.update((unsigned char*)buf, strlen(buf));
            context.finalize();

            sprintf(query, "INSERT INTO customers (username, password, cc1_type, cc1_number, spam) VALUES ('%s', '%s', 'asiV', '1', 1);",
                    buf, context.hex_digest());
    
            if (!dbase_->dbQuery(query))
            {
                Sys_LogError("Query to create test player failed(1).");
                return false;
            }        

            sprintf(query, "INSERT INTO pokeruser (username, password) VALUES ('%s', '%s');",
                    buf, context.hex_digest());
    
            if (!dbase_->dbQuery(query))
            {
                Sys_LogError("Query to create test player failed(2).");
                return false;
            }        
        }
    }

    return true;
}
Ejemplo n.º 2
0
const wxString wxMD5::GetDigest()
{
	MD5 context;
	context.update((unsigned char*)m_szText.mb_str().data(), m_szText.Len());
	context.finalize();
	
	wxString md5(context.hex_digest());
	md5.MakeUpper();
	return md5;
}
Ejemplo n.º 3
0
bool CdbInterface::authenticate(const char* username, const char* password)
{
    SingleLock l(&dbMutex_);
    if (!l.lock())
        return false;

    ReadLockSQLTable sqlLock(dbase_, "pokeruser");
    if (!sqlLock.success_)
        return false;

    char query[MAXQUERYSIZE];
    char* dbPassword = NULL;
    MD5 context;

    string u = sqlfy(username);

    context.update((unsigned char *)password, (int)strlen(password));
    context.finalize();


    memset(query, 0x0, MAXQUERYSIZE);

    sprintf(query, "SELECT password FROM pokeruser WHERE username='******'", u.c_str());
    
    if (!dbase_->dbQuery(query))
    {
        if (DEBUG & DEBUG_DATABASE)
        {
            printf("Query to authenticate %s failed!\n", username);
            printf("Reason: %s\n", mysql_error(dbase_->mySQLQuery_));
        }
        return false;
    }

    dbPassword = dbase_->dbFetchRow();

    if (dbPassword == NULL)
    {
        char s[200];
        sprintf(s, "CTable::tableLogin: User %s does not exist in database!", username);
        Sys_LogError(s);
        return false;
    }
    else if (strcmp(dbPassword, context.hex_digest()))
    {
        char s[200];
        sprintf(s, "CTable::tableLogin: wrong password %s for user %s.", password, username);
        Sys_LogError(s);
        return false;
    }

    return true;
};
Ejemplo n.º 4
0
bool CdbInterface::authenticate(const char* username, const char* password)
{
  ReadLockSQLTable sqlLock(dbase_, "pokeruser");
  
  CStrOut query;
  char* dbPassword = NULL;
  
  string u = sqlfy(username);
  
  MD5 context;
  context.update((unsigned char*)password, strlen(password));
  context.finalize();
  
  query << "SELECT password FROM pokeruser WHERE username='******'\'';
  
  if (!dbase_->dbQuery(query.str()))
  {
    if (DEBUG & DEBUG_DATABASE)
    {
      printf("Query to authenticate %s failed!\n", username);
    }
    
    return false;
  }
  
  dbPassword = dbase_->dbFetchRow();
  
  if (dbPassword == NULL)
  {
    if (DEBUG & DEBUG_DATABASE)
    {
      printf("User %s does not exist in database!\n", username);
    }
    
    return false;
    
  }
  else if (strcmp(dbPassword, context.hex_digest()))
  {
    if (DEBUG & DEBUG_DATABASE)
    {
      printf("User supplied password and password on file don't match!\n");            
    }
    return false;
  }
  
  return true;
};
Ejemplo n.º 5
0
int main( int argc, char* argv[ ] )
{
   int first_arg = 0;
   bool prune = false;
   bool recurse = false;
   bool invalid = false;
   bool is_quiet = false;
   bool use_zlib = true;
   bool is_delete = false;
   bool is_quieter = false;

   string open_mode( "wb" );

#ifndef ZLIB_SUPPORT
   encoding_type encoding = e_encoding_type_esc;
#else
   encoding_type encoding = e_encoding_type_raw;
#endif

   if( argc > first_arg + 1 )
   {
      if( string( argv[ first_arg + 1 ] ) == "-0" )
      {
         ++first_arg;
         open_mode += "0";
      }
      else if( string( argv[ first_arg + 1 ] ) == "-1" )
      {
         ++first_arg;
         open_mode += "1";
      }
      else if( string( argv[ first_arg + 1 ] ) == "-9" )
      {
         ++first_arg;
         open_mode += "9";
      }
   }

   if( argc > first_arg + 1 )
   {
      if( string( argv[ first_arg + 1 ] ) == "-d" )
      {
         ++first_arg;
         is_delete = true;
      }
   }

   if( !is_delete )
   {
      if( argc > first_arg + 1 )
      {
         if( string( argv[ first_arg + 1 ] ) == "-r" )
         {
            ++first_arg;
            recurse = true;
         }
      }

      if( argc > first_arg + 1 )
      {
         if( string( argv[ first_arg + 1 ] ) == "-p" )
         {
            ++first_arg;
            prune = true;

            if( !recurse )
               invalid = true;
         }
      }
   }

   if( argc > first_arg + 1 )
   {
      if( string( argv[ first_arg + 1 ] ) == "-q" )
      {
         ++first_arg;
         is_quiet = true;
      }
   }

   if( argc > first_arg + 1 )
   {
      if( string( argv[ first_arg + 1 ] ) == "-qq" )
      {
         ++first_arg;
         is_quiet = true;
         is_quieter = true;
      }
   }

   if( argc > first_arg + 1 )
   {
      // NOTE: Ignore '-y' for compatibility with zip.
      if( string( argv[ first_arg + 1 ] ) == "-y" )
         ++first_arg;
   }

   if( argc > first_arg + 1 )
   {
      if( string( argv[ first_arg + 1 ] ) == "-b64" )
      {
         ++first_arg;
         encoding = e_encoding_type_b64;
      }
      else if( string( argv[ first_arg + 1 ] ) == "-esc" )
      {
         ++first_arg;
         encoding = e_encoding_type_esc;
      }
   }

#ifdef ZLIB_SUPPORT
   if( argc > first_arg + 1 )
   {
      if( string( argv[ first_arg + 1 ] ) == "-ngz" )
      {
         ++first_arg;
         use_zlib = false;
      }
   }
#endif

   if( !is_quiet )
      cout << "bundle v0.1e\n";

   if( invalid || ( argc - first_arg < 2 )
    || string( argv[ 1 ] ) == "?" || string( argv[ 1 ] ) == "/?" || string( argv[ 1 ] ) == "-?" )
   {
#ifndef ZLIB_SUPPORT
      cout << "usage: bundle [-0|-1|-9] [-d]|[-r [-p]] [-q[q]] [-b64|-esc] <fname> [<fspec1> [<fspec2> [...]]] [-x <fspec1> [...]]" << endl;
#else
      cout << "usage: bundle [-0|-1|-9] [-d]|[-r [-p]] [-q[q]] [-b64|-esc] [-ngz] <fname> [<fspec1> [<fspec2> [...]]] [-x <fspec1> [...]]" << endl;
#endif

      cout << "\nwhere: -0/-1/-9 is used for setting zero/fastest/best compression level" << endl;
      cout << "  and: -d is to delete matching files which exist in an existing bundle" << endl;
      cout << "  and: -r is to recurse sub-directories (-p to prune empty directories)" << endl;
      cout << "  and: -q for quiet mode (-qq to suppress all output apart from errors)" << endl;
      cout << "  and: -b64/-esc stores file data using b64/esc encoding for text lines" << endl;
#ifdef ZLIB_SUPPORT
      cout << "  and: -ngz in order to not preform zlib compression" << endl;
#endif
      cout << " also: -x identifies one or more filespecs that are to be excluded" << endl;
      return 0;
   }

   try
   {
      g_cwd = get_cwd( );

      string::size_type pos;

#ifdef _WIN32
      while( ( pos = g_cwd.find( '\\' ) ) != string::npos )
         g_cwd[ pos ] = '/';
#endif

      pos = g_cwd.find_last_of( '/' );

      if( is_root_path( g_cwd ) )
         throw runtime_error( "cannot created a bundle in the root directory" );

      map< string, vector< string > > all_filespecs;
      map< string, vector< string > > all_exclude_filespecs;

      string filename( argv[ first_arg + 1 ] );

      if( !filename.empty( ) && filename[ 0 ] == '-' )
         throw runtime_error( "unknown or bad option '" + filename + "' use -? to see options" );

      string ext( c_default_extension );
      if( use_zlib )
         ext += c_zlib_extension;

      if( filename.find( ext ) == string::npos )
         filename += ext;

      bool get_exclude_filespecs = false;
      string directory = g_cwd.substr( pos + 1 );

      if( !is_delete )
      {
         for( int i = first_arg + 2; i < argc; i++ )
         {
            string next( argv[ i ] );

            if( !next.empty( ) && next[ 0 ] == '-' )
            {
               if( next == "-x" && !get_exclude_filespecs )
               {
                  next.erase( );
                  get_exclude_filespecs = true;
               }
               else
                  throw runtime_error( "unknown or bad option '" + next + "' use -? to see options" );
            }

            if( !next.empty( ) )
            {
               string::size_type wpos = next.find_first_of( "?*" );

               string filespec_path;
               if( wpos == 0 )
               {
                  filespec_path = g_cwd + "/" + next;
                  wpos = string::npos;
               }
               else
               {
                  if( !absolute_path( next.substr( 0, wpos ), filespec_path ) )
                     throw runtime_error( "unable to determine absolute path for '" + next + "'" );
               }

#ifdef _WIN32
               string::size_type pos;
               while( ( pos = filespec_path.find( '\\' ) ) != string::npos )
                  filespec_path[ pos ] = '/';
#endif

               if( is_root_path( filespec_path ) )
                  throw runtime_error( "cannot bundle directory '" + next + "' (need to specify a non-root directory)" );

               if( wpos != string::npos )
#ifdef _WIN32
                  filespec_path += next.substr( wpos );
#else
                  filespec_path += "/" + next.substr( wpos );
#endif
               string::size_type rpos = filespec_path.find_last_of( '/' );

               string filename_filter;
               if( rpos != string::npos )
               {
                  filename_filter = filespec_path.substr( rpos + 1 );
                  filespec_path.erase( rpos );
               }

               if( recurse == true
                && filespec_path.length( ) > g_cwd.length( ) && filespec_path.find( g_cwd ) == 0 )
               {
                  filename_filter = filespec_path.substr( g_cwd.length( ) + 1 ) + "/" + filename_filter;
                  filespec_path = g_cwd;
               }

               if( !get_exclude_filespecs )
                  all_filespecs[ filespec_path ].push_back( filename_filter );
               else
                  all_exclude_filespecs[ filespec_path ].push_back( filename_filter );
            }
         }

         if( all_filespecs.empty( ) )
            all_filespecs[ g_cwd ].push_back( "*" );
      }

      int num_deleted = 0;

      set< string > file_names;
      set< string > matched_filters;

      bool is_append = false;
      if( file_exists( filename ) )
         is_append = true;

      if( is_delete && first_arg + 2 >= argc )
         throw runtime_error( "cannot delete files without specifying at least one filespec" );

      if( is_delete && !is_append )
         throw runtime_error( "no bundle file '" + filename + "' was found" );

      string output_filename( filename );
      if( is_append )
         output_filename = output_filename + ".tmp";

      // NOTE: Empty code block for scope purposes.
      {
#ifndef ZLIB_SUPPORT
         ofstream outf( output_filename.c_str( ) );
         if( !outf )
            throw runtime_error( "unable to open file '" + output_filename + "' for output" );
#else
         gzFile gzf;
         ofstream outf;

         if( !use_zlib )
            outf.open( output_filename.c_str( ) );
         else
            gzf = gzopen( output_filename.c_str( ), open_mode.c_str( ) );

         if( ( use_zlib && !gzf ) || ( !use_zlib && !outf ) )
            throw runtime_error( "unable to open file '" + output_filename + "' for output" );
#endif

         if( !is_quiet )
         {
            if( !is_append )
               cout << "==> started bundling '" << filename << "'\n";
            else
               cout << "==> continue bundling '" << filename << "'\n";
         }

         absolute_path( filename, g_bundle_file_name );
         absolute_path( output_filename, g_output_file_name );

         string header( "B " );
         header += to_string( c_format_version );

         switch( encoding )
         {
            case e_encoding_type_b64:
            header += " B64";
            break;

            case e_encoding_type_esc:
            header += " ESC";
            break;

            case e_encoding_type_raw:
            header += " RAW";
            break;
         }

#ifndef ZLIB_SUPPORT
         outf << header << '\n';
#else
         if( !use_zlib )
            outf << header << '\n';
         else
            write_zlib_line( gzf, header );
#endif

         if( !is_delete )
         {
            for( map< string, vector< string > >::iterator i = all_filespecs.begin( ); i != all_filespecs.end( ); ++i )
            {
               string filespec_path( i->first );
               vector< string >& filename_filters( i->second );

               vector< string >* p_filename_exclusions = 0;
               if( all_exclude_filespecs.count( i->first ) )
                  p_filename_exclusions = &all_exclude_filespecs[ i->first ];

#ifndef ZLIB_SUPPORT
               process_directory( directory, filespec_path, filename_filters, p_filename_exclusions,
                matched_filters, file_names, recurse, prune, is_quieter, is_append, encoding, outf );
#else
               process_directory( directory, filespec_path, filename_filters, p_filename_exclusions,
                matched_filters, file_names, recurse, prune, is_quieter, is_append, encoding, outf, use_zlib, gzf );
#endif
               if( !is_quieter )
               {
                  for( size_t i = 0; i < filename_filters.size( ); i++ )
                  {
                     if( matched_filters.count( filename_filters[ i ] ) == 0 )
                        cout << "warning: found no files matching '" << filename_filters[ i ] << "'" << endl;
                  }
               }
            }
         }

         if( is_append )
         {
#ifdef ZLIB_SUPPORT
            gzFile igzf;
            ifstream inpf;

            if( !use_zlib )
               inpf.open( filename.c_str( ) );
            else
               igzf = gzopen( filename.c_str( ), "rb" );

            if( ( use_zlib && !igzf ) || ( !use_zlib && !inpf ) )
               throw runtime_error( "unable to open file '" + filename + "' for input" );
#else
            ifstream inpf( filename.c_str( ) );
            if( !inpf )
               throw runtime_error( "unable to open file '" + filename + "' for input" );
#endif

            encoding_type old_encoding;
#ifndef ZLIB_SUPPORT
            check_file_header( inpf, filename, old_encoding );
#else
            check_file_header( inpf, filename, old_encoding, use_zlib, igzf );
#endif

            if( old_encoding != encoding )
               throw runtime_error( "*** cannot combine different bundle data encoding types ***" );

            string next;
            int line = 0;
            int count = 0;
            int line_size = 0;
            int file_data_lines = 0;
            int64_t raw_file_size = 0;
            bool skip_existing_file = false;

            string current_sub_path;

            while( true )
            {
               if( raw_file_size )
               {
                  if( skip_existing_file )
                  {
#ifdef ZLIB_SUPPORT
                     if( use_zlib )
                        gzseek( igzf, raw_file_size, SEEK_CUR );
                     else
                        inpf.seekg( raw_file_size, ios::cur );
#else
                     inpf.seekg( raw_file_size, ios::cur );
#endif
                     raw_file_size = 0;
                  }
                  else
                  {
                     int64_t chunk = 0;
                     while( raw_file_size > 0 )
                     {
                        char buffer[ c_buffer_size ];

                        int count = c_buffer_size;
                        if( raw_file_size < c_buffer_size )
                           count = raw_file_size;

#ifdef ZLIB_SUPPORT
                        if( use_zlib )
                        {
                           if( !gzread( igzf, buffer, count ) )
                              throw runtime_error( "reading zlib input" );
                        }
                        else
                        {
                           if( inpf.rdbuf( )->sgetn( buffer, count ) != count )
                              throw runtime_error( "reading file input" );
                        }
#else
                        if( inpf.rdbuf( )->sgetn( buffer, count ) != count )
                           throw runtime_error( "reading file input" );
#endif

                        if( !is_quieter && ++chunk % c_progress_lines == 0 )
                        {
                           if( line == c_progress_lines )
                              cout << ' ';
                           cout << '.';
                           cout.flush( );
                        }

#ifndef ZLIB_SUPPORT
                        outf.rdbuf( )->sputn( buffer, count );
                        if( !outf.good( ) )
                           throw runtime_error( "unexpected bad output file stream" );
#else
                        if( !use_zlib )
                        {
                           outf.rdbuf( )->sputn( buffer, count );

                           if( !outf.good( ) )
                              throw runtime_error( "unexpected bad output file stream" );
                        }
                        else if( !gzwrite( gzf, buffer, count ) )
                           throw runtime_error( "writing zlib block" );
#endif

                        raw_file_size -= count;
                     }

                     if( !is_quieter )
                        cout << endl;

                     continue;
                  }
               }

#ifdef ZLIB_SUPPORT
               if( use_zlib )
               {
                  if( !read_zlib_line( igzf, next, false ) )
                     break;
               }
               else if( !getline( inpf, next ) )
                  break;
#else
               if( !getline( inpf, next ) )
                  break;
#endif
               ++line;
               if( file_data_lines )
               {
                  --file_data_lines;

                  if( count == 0 )
                     line_size = unescaped( next ).size( );

                  // NOTE: If skipping a file then there is no need to actually
                  // read the data so by determining the line size of the first
                  // line (after unescaping) it is safe to "seek" one byte less
                  // forwards and then read the remainder of the line (the size
                  // of this will depend upon how much escaping is being used).
                  if( skip_existing_file && line_size && file_data_lines > 1 )
                  {
#ifdef ZLIB_SUPPORT
                     if( use_zlib )
                        gzseek( igzf, line_size - 1, SEEK_CUR );
                     else
                        inpf.seekg( line_size - 1, ios::cur );
#else
                     inpf.seekg( line_size - 1, ios::cur );
#endif
                  }

                  if( ++count % c_progress_lines == 0 && !is_quieter && !skip_existing_file )
                  {
                     if( count == c_progress_lines )
                        cout << ' ';
                     cout << '.';
                     cout.flush( );
                  }

                  if( !is_quieter && !skip_existing_file && file_data_lines == 0 )
                     cout << endl;

                  if( !skip_existing_file )
                  {
#ifndef ZLIB_SUPPORT
                     outf << line << '\n';
#else
                     if( !use_zlib )
                        outf << next << '\n';
                     else
                        write_zlib_line( gzf, next );
#endif
                  }
               }
               else
               {
                  string::size_type pos = next.find( ' ' );
                  if( pos != 1 )
                     throw runtime_error( "unexpected format in line #" + to_string( line ) );

                  char type( next[ 0 ] );

                  string next_line( next );

                  if( type == c_type_file )
                  {
                     next.erase( 0, 2 );
                     pos = next.find( ' ' );
                     if( pos == string::npos )
                        throw runtime_error( "unexpected format in line #" + to_string( line ) );

                     if( encoding == e_encoding_type_raw )
                        raw_file_size = unformat_bytes( next.substr( 0, pos ) );
                     else
                     {
                        int num_lines( atoi( next.substr( 0, pos ).c_str( ) ) );
                        if( num_lines < 0 )
                           throw runtime_error( "invalid number of lines "
                            + to_string( num_lines ) + " specified in line #" + to_string( line ) );

                        file_data_lines = num_lines;
                     }

                     next.erase( 0, pos + 1 );

                     string::size_type pos = next.find_last_of( " " );
                     if( pos == string::npos )
                        throw runtime_error( "unexpected file entry format in line #" + to_string( line ) );

                     string check = next.substr( pos + 1 );
                     next.erase( pos );

                     pos = next.find( ' ' );
                     if( pos == string::npos )
                        throw runtime_error( "unexpected file entry format in line #" + to_string( line ) );

                     string rwx_perms( next.substr( 0, pos ) );
                     next.erase( 0, pos + 1 );

                     count = 0;

                     if( is_delete )
                     {
                        bool matched = false;
                        vector< string >& exprs( all_filespecs[ c_delete_dummy_path ] );

                        string next_path( current_sub_path + '/' + next );
                        for( size_t i = 0; i < exprs.size( ); i++ )
                        {
                           if( wildcard_match( exprs[ i ], next_path ) )
                           {
                              if( !is_quieter )
                                 cout << "*kill* \"" << next << "\"" << endl;
                              ++num_deleted;
                              matched = true;
                              break;
                           }
                        }

                        if( matched )
                        {
                           skip_existing_file = true;
                           continue;
                        }
                     }

                     pos = current_sub_path.find( '/' );
                     if( pos != string::npos )
                        next = current_sub_path.substr( pos + 1 ) + '/' + next;

                     if( file_names.count( next ) )
                     {
                        skip_existing_file = true;
                        continue;
                     }
                     else
                     {
                        skip_existing_file = false;

                        if( !is_quieter )
                           cout << "append \"" << next << "\"";

                        file_names.insert( next );
                        g_md5.update( ( unsigned char* )check.c_str( ), check.length( ) );
                     }
                  }
                  else if( type == c_type_directory )
                  {
                     next.erase( 0, 2 );
                     pos = next.find( ' ' );
                     if( pos == string::npos )
                        throw runtime_error( "unexpected format in line #" + to_string( line ) );

                     string::size_type cpos = next.find_last_of( ' ' );
                     if( cpos == pos || cpos == string::npos )
                        throw runtime_error( "unexpected format in line #" + to_string( line ) );

                     string check( next.substr( cpos + 1 ) );
                     next.erase( cpos );

                     pos = next.find( ' ' );
                     if( pos == string::npos )
                        throw runtime_error( "unexpected format in line #" + to_string( line ) );

                     int next_level( atoi( next.substr( 0, pos ).c_str( ) ) );
                     next.erase( 0, pos + 1 );

                     pos = next.find( ' ' );
                     if( pos == string::npos )
                        throw runtime_error( "unexpected format in line #" + to_string( line ) );

                     string rwx_perms( next.substr( 0, pos ) );
                     next.erase( 0, pos + 1 );

                     if( is_delete && all_filespecs.empty( ) )
                     {
                        for( int i = first_arg + 2; i < argc; i++ )
                           all_filespecs[ c_delete_dummy_path ].push_back( next + '/' + string( argv[ i ] ) );
                     }

                     current_sub_path = next;

                     if( file_names.count( next ) )
                        continue;
                     else
                     {
                        pos = next.find( '/' );
                        if( !is_quieter && pos != string::npos )
                           cout << "append \"" << next.substr( pos + 1 ) << "/\"\n";

                        file_names.insert( next );
                        g_md5.update( ( unsigned char* )check.c_str( ), check.length( ) );
                     }
                  }
                  else if( type == c_type_checksum )
                     break;
                  else
                     throw runtime_error( "unexpected entry type '" + to_string( type ) + "' found in line #" + to_string( line ) );

#ifndef ZLIB_SUPPORT
                  outf << next_line << '\n';
#else
                  if( !use_zlib )
                     outf << next_line << '\n';
                  else
                     write_zlib_line( gzf, next_line );
#endif
               }
            }

#ifdef ZLIB_SUPPORT
            if( use_zlib )
               gzclose( igzf );
#endif
         }

         g_md5.finalize( );
         ostringstream osstr;
         auto_ptr< char > ap_digest( g_md5.hex_digest( ) );

         osstr << "C " << ap_digest.get( );

#ifndef ZLIB_SUPPORT
         outf << osstr.str( ) << '\n';
#else
         if( !use_zlib )
            outf << osstr.str( ) << '\n';
         else
            write_zlib_line( gzf, osstr.str( ) );
#endif

#ifdef ZLIB_SUPPORT
         if( use_zlib )
            gzclose( gzf );
#endif

         if( !use_zlib )
         {
            outf.flush( );
            if( !outf.good( ) )
               throw runtime_error( "unexpected write failure for output file '" + filename + "'" );
         }
      }

      if( is_append )
      {
         if( !file_remove( filename ) || rename( output_filename.c_str( ), filename.c_str( ) ) != 0 )
            throw runtime_error( "unable to replace original '" + filename + "' with '" + output_filename + "'" );

         if( is_delete && !is_quieter && num_deleted == 0 )
            cout << "warning: found no matching files to delete" << endl;
      }
      else if( matched_filters.empty( ) )
      {
         file_remove( filename );
         throw runtime_error( "*** nothing to do ***" );
      }

      if( !is_quiet )
         cout << "==> finished bundling '" << filename << "'" << endl;
   }
   catch( exception& x )
   {
      cerr << "error: " << x.what( ) << endl;
      return 1;
   }

   return 0;
}
Ejemplo n.º 6
0
int main( int argc, char* argv[ ] )
{
    int first_arg = 0;
    bool junk = false;
    bool prune = false;
    bool include = false;
    bool use_zlib = false;
    bool is_quiet = false;
    bool list_only = false;
    bool overwrite = false;
    bool is_quieter = false;

    if( argc > first_arg + 1 )
    {
        if( string( argv[ first_arg + 1 ] ) == "-i" )
        {
            ++first_arg;
            junk = true;
        }
        else if( string( argv[ first_arg + 1 ] ) == "-j" )
        {
            ++first_arg;
            include = true;
        }
    }

    if( argc > first_arg + 1 )
    {
        if( string( argv[ first_arg + 1 ] ) == "-l" )
        {
            ++first_arg;
            list_only = true;
        }
    }

    if( argc > first_arg + 1 )
    {
        if( string( argv[ first_arg + 1 ] ) == "-o" )
        {
            ++first_arg;
            overwrite = true;
        }
    }

    if( argc > first_arg + 1 )
    {
        if( string( argv[ first_arg + 1 ] ) == "-p" )
        {
            ++first_arg;
            prune = true;
        }
    }

    if( argc > first_arg + 1 )
    {
        if( string( argv[ first_arg + 1 ] ) == "-q" )
        {
            ++first_arg;
            is_quiet = true;
        }
    }

    if( argc > first_arg + 1 )
    {
        if( string( argv[ first_arg + 1 ] ) == "-qq" )
        {
            ++first_arg;
            is_quiet = true;
            is_quieter = true;
        }
    }

    if( !is_quiet )
        cout << "unbundle v0.1d\n";

    if( ( argc - first_arg < 2 )
            || string( argv[ 1 ] ) == "?" || string( argv[ 1 ] ) == "/?" || string( argv[ 1 ] ) == "-?" )
    {
        cout << "usage: unbundle [-i|-j] [-l] [-o] [-p] [-q[q]] <fname> [<fspec1> [<fspec2> [...]]] [-x <fspec1> [...]] [-d <directory>]" << endl;

        cout << "\nwhere: -i to include top level directory and -j to junk all directories" << endl;
        cout << "  and: -l to list rather than create all matching files and directories" << endl;
        cout << "  and: -o to overwrite existing files and -p to prune empty directories" << endl;
        cout << "  and: -q for quiet mode (-qq to suppress all output apart from errors)" << endl;
        cout << "  and: -x identifies one or more filespecs that are to be excluded" << endl;
        cout << " also: -d <directory> to set a directory origin for output" << endl;
        return 0;
    }

#ifdef __GNUG__
    umask( DEFAULT_UMASK );
#endif

    try
    {
        string filename( argv[ first_arg + 1 ] );

        if( !filename.empty( ) && filename[ 0 ] == '-' )
            throw runtime_error( "unknown or bad option '" + filename + "' use -? to see options" );

        if( filename.length( ) > 3
                && filename.substr( filename.length( ) - 3 ) == string( c_zlib_extension ) )
        {
#ifdef ZLIB_SUPPORT
            use_zlib = true;
#else
            throw runtime_error( "this program has not been compiled with ZLIB support" );
#endif
        }

        string::size_type pos = filename.find( '.' );

        if( pos == string::npos || _access( filename.c_str( ), 0 ) != 0 )
            filename += c_default_extension;

#ifdef ZLIB_SUPPORT
        if( _access( filename.c_str( ), 0 ) != 0 )
        {
            use_zlib = true;
            filename += c_zlib_extension;
        }

        gzFile gzf;
        ifstream inpf;

        if( !use_zlib )
            inpf.open( filename.c_str( ) );
        else
            gzf = gzopen( filename.c_str( ), "rb" );

        if( ( use_zlib && !gzf ) || ( !use_zlib && !inpf ) )
            throw runtime_error( "unable to open file '" + filename + "' for input" );
#else
        ifstream inpf( filename.c_str( ) );
        if( !inpf )
            throw runtime_error( "unable to open file '" + filename + "' for input" );
#endif

        if( !is_quiet && !list_only )
            cout << "==> started unbundling '" << filename << "'\n";

        bool get_exclude_filespecs = false;

        string destination_directory;
        bool get_destination_directory = false;

        vector< string > filename_filters;
        vector< string > exclude_filename_filters;
        for( int i = first_arg + 2; i < argc; i++ )
        {
            string next( argv[ i ] );

            if( !next.empty( ) && next[ 0 ] == '-' )
            {
                if( next == "-d" && !get_destination_directory )
                {
                    next.erase( );
                    get_destination_directory = true;
                }
                else if( next == "-x" && !get_exclude_filespecs )
                {
                    next.erase( );
                    get_exclude_filespecs = true;
                }
                else
                    throw runtime_error( "unknown or bad option '" + next + "' use -? to see options" );
            }

            if( !next.empty( ) )
            {
                if( get_destination_directory && destination_directory.empty( ) )
                {
                    destination_directory = next;
#ifndef _WIN32
                    if( destination_directory[ destination_directory.size( ) - 1 ] != '/' )
                        destination_directory += '/';
#else
                    if( destination_directory[ destination_directory.size( ) - 1 ] != '/'
                            && destination_directory[ destination_directory.size( ) - 1 ] != '\\'
                            && destination_directory[ destination_directory.size( ) - 1 ] != ':' )
                        destination_directory += '/';

                    replace( destination_directory, "\\", "/" );
#endif
                }
                else if( get_exclude_filespecs )
                    exclude_filename_filters.push_back( next );
                else
                    filename_filters.push_back( next );
            }
        }

        int level = -1;
        bool is_first = false;

        string next_file;
        string rwx_perms;
        int line_size = 0;
        int file_data_lines = 0;
        int64_t raw_file_size = 0;

        stack< string > paths;
        deque< string > create_directories;
        map< string, string > directory_perms;

        set< string > created;
        set< string > matched_filters;

        auto_ptr< ofstream > ap_ofstream;

        MD5 md5;
        string next;
        string next_md5;
        size_t line = 1;
        size_t count = 0;

        bool finished = false;
        bool replace_all = false;
        bool replace_none = false;

        encoding_type encoding;
        string top_level_directory;

        int progress = c_progress_lines;

#ifndef ZLIB_SUPPORT
        check_file_header( inpf, filename, encoding );
#else
        check_file_header( inpf, filename, encoding, use_zlib, gzf );
#endif

        while( true )
        {
            if( raw_file_size )
            {
                if( !ap_ofstream.get( ) )
                {
#ifdef ZLIB_SUPPORT
                    if( use_zlib )
                        gzseek( gzf, raw_file_size, SEEK_CUR );
                    else
                        inpf.seekg( raw_file_size, ios::cur );
#else
                    inpf.seekg( raw_file_size, ios::cur );
#endif
                    raw_file_size = 0;
                }
                else
                {
                    int64_t chunk = 0;
                    while( raw_file_size > 0 )
                    {
                        char buffer[ c_buffer_size ];

                        int count = c_buffer_size;
                        if( raw_file_size < c_buffer_size )
                            count = raw_file_size;

#ifdef ZLIB_SUPPORT
                        if( use_zlib )
                        {
                            if( !gzread( gzf, buffer, count ) )
                                throw runtime_error( "reading zlib input" );
                        }
                        else
                        {
                            if( inpf.rdbuf( )->sgetn( buffer, count ) != count )
                                throw runtime_error( "reading file input" );
                        }
#else
                        if( inpf.rdbuf( )->sgetn( buffer, count ) != count )
                            throw runtime_error( "reading file input" );
#endif

                        if( !is_quieter && ++chunk % c_progress_lines == 0 )
                        {
                            if( line == c_progress_lines )
                                cout << ' ';
                            cout << '.';
                            cout.flush( );
                        }

                        md5.update( ( unsigned char* )buffer, count );

                        ap_ofstream->rdbuf( )->sputn( buffer, count );
                        if( !ap_ofstream->good( ) )
                            throw runtime_error( "unexpected bad output file stream" );

                        raw_file_size -= count;
                    }

                    md5.finalize( );
                    auto_ptr< char > ap_digest( md5.hex_digest( ) );

                    if( next_md5 != string( ap_digest.get( ) ) )
                        cerr << "*** error: file '" << next_file << "' failed MD5 digest check ***" << endl;

                    ap_ofstream.reset( );
                    file_perms( next_file, rwx_perms );

                    if( !is_quieter )
                        cout << endl;

                    continue;
                }
            }

#ifdef ZLIB_SUPPORT
            if( use_zlib )
            {
                if( !read_zlib_line( gzf, next ) )
                    break;
            }
            else if( !getline( inpf, next ) )
                break;
#else
            if( !getline( inpf, next ) )
                break;
#endif
            ++line;

            if( next.empty( ) )
                throw runtime_error( "unexpected empty line #" + to_string( line ) );

            if( file_data_lines )
            {
                --file_data_lines;

                if( count == 0 )
                {
                    line_size = unescaped( next ).size( );

                    if( line_size >= 1048576 ) // i.e. 1 MB
                        progress = 2;
                    else
                        progress = c_progress_lines;
                }

                // NOTE: If skipping a file then there is no need to actually
                // read the data so by determining the line size of the first
                // line (after unescaping) it is safe to "seek" one byte less
                // forwards and then read the remainder of the line (the size
                // of this will depend upon how much escaping is being used).
                if( !ap_ofstream.get( ) && line_size && file_data_lines > 1 )
                {
#ifdef ZLIB_SUPPORT
                    if( use_zlib )
                        gzseek( gzf, line_size - 1, SEEK_CUR );
                    else
                        inpf.seekg( line_size - 1, ios::cur );
#else
                    inpf.seekg( line_size - 1, ios::cur );
#endif
                }

                if( ++count % progress == 0 && !is_quieter && ap_ofstream.get( ) )
                {
                    if( count == progress )
                        cout << ' ';
                    cout << '.';
                    cout.flush( );
                }

                if( !is_quieter && ap_ofstream.get( ) && file_data_lines == 0 )
                    cout << endl;

                if( ap_ofstream.get( ) )
                {
                    string fdata;

                    if( use_zlib )
                        fdata = next;
                    else if( encoding != e_encoding_type_b64 )
                        fdata = unescaped_line( next );
                    else
                        fdata = base64::decode( next );

                    if( ap_ofstream->rdbuf( )->sputn( fdata.c_str( ), fdata.length( ) ) != ( int )fdata.length( ) )
                        throw runtime_error( "write failed for file '" + next_file + "'" );

                    md5.update( ( unsigned char* )fdata.c_str( ), fdata.length( ) );

                    if( file_data_lines == 0 )
                    {
                        ap_ofstream->flush( );
                        if( !ap_ofstream->good( ) )
                            throw runtime_error( "flush failed for file '" + next_file + "'" );
                        ap_ofstream->close( );

                        ap_ofstream.reset( );
                        file_perms( next_file, rwx_perms );

                        md5.finalize( );
                        auto_ptr< char > ap_digest( md5.hex_digest( ) );

                        if( next_md5 != string( ap_digest.get( ) ) )
                            cerr << "*** error: file '" << next_file << "' failed MD5 digest check ***" << endl;
                    }
                }

                continue;
            }

            if( finished )
                throw runtime_error( "unexpected end of file not found at line #" + to_string( line ) );

            string::size_type pos = next.find( ' ' );
            if( pos != 1 )
                throw runtime_error( "unexpected format in line #" + to_string( line ) );

            char type( next[ 0 ] );
            if( type == c_type_file )
            {
                if( is_first )
                    throw runtime_error( "unexpected file entry in line #" + to_string( line ) );

                md5.init( );

                next.erase( 0, 2 );
                pos = next.find( ' ' );
                if( pos == string::npos )
                    throw runtime_error( "unexpected format in line #" + to_string( line ) );

                if( encoding == e_encoding_type_raw )
                    raw_file_size = unformat_bytes( next.substr( 0, pos ) );
                else
                {
                    int num_lines( atoi( next.substr( 0, pos ).c_str( ) ) );
                    if( num_lines < 0 )
                        throw runtime_error( "invalid number of lines "
                                             + to_string( num_lines ) + " specified in line #" + to_string( line ) );

                    file_data_lines = num_lines;
                }

                next.erase( 0, pos + 1 );

                string::size_type pos = next.find_last_of( " " );
                if( pos == string::npos )
                    throw runtime_error( "unexpected file entry format in line #" + to_string( line ) );

                next_md5 = next.substr( pos + 1 );
                next.erase( pos );

                g_md5.update( ( unsigned char* )next_md5.c_str( ), next_md5.length( ) );

                pos = next.find( ' ' );
                if( pos == string::npos )
                    throw runtime_error( "unexpected file entry format in line #" + to_string( line ) );

                rwx_perms = next.substr( 0, pos );
                next.erase( 0, pos + 1 );

                string test_file( next );
                if( !paths.empty( ) )
                    test_file = paths.top( ) + "/" + next;

                if( junk )
                    next_file = destination_directory + next;
                else
                    next_file = destination_directory + test_file;

                md5.update( ( unsigned char* )rwx_perms.c_str( ), rwx_perms.length( ) );
                md5.update( ( unsigned char* )next.c_str( ), next.length( ) );

                bool matched = false;
                if( filename_filters.empty( ) )
                    matched = true;
                else
                {
                    for( size_t i = 0; i < filename_filters.size( ); i++ )
                    {
                        string wildcard( filename_filters[ i ] );

                        string::size_type pos = wildcard.find( "/" );
                        if( pos == string::npos )
                        {
                            pos = test_file.find_last_of( "/" );
                            if( pos != string::npos )
                                test_file.erase( 0, pos + 1 );
                        }
                        else if( junk )
                        {
                            if( wildcard.find( top_level_directory + "/" ) != 0 )
                                wildcard = top_level_directory + "/" + wildcard;
                        }

                        if( wildcard_match( wildcard, test_file ) )
                        {
                            matched = true;
                            matched_filters.insert( filename_filters[ i ] );

                            break;
                        }
                    }
                }

                if( !exclude_filename_filters.empty( ) )
                {
                    for( size_t i = 0; i < exclude_filename_filters.size( ); i++ )
                    {
                        string wildcard( exclude_filename_filters[ i ] );

                        string::size_type pos = wildcard.find( "/" );
                        if( pos == string::npos )
                        {
                            pos = test_file.find_last_of( "/" );
                            if( pos != string::npos )
                                test_file.erase( 0, pos + 1 );
                        }
                        else if( junk )
                        {
                            if( wildcard.find( top_level_directory + "/" ) != 0 )
                                wildcard = top_level_directory + "/" + wildcard;
                        }

                        if( wildcard_match( wildcard, test_file ) )
                        {
                            matched = false;
                            break;
                        }
                    }
                }

                if( matched && !list_only && !overwrite && !replace_all && file_exists( next_file ) )
                {
                    bool replace = false;
                    if( !is_quiet && !replace_none )
                    {
                        char ch;
                        string prompt( "File '" + next_file + "' already exists. Replace [y/n/A/N]? " );
                        while( true )
                        {
                            ch = get_char( prompt.c_str( ) );

                            if( ch == 'A' )
                                replace_all = true;
                            else if( ch == 'N' )
                                replace_none = true;

                            if( ch == 'y' || ch == 'A' )
                                replace = true;

                            if( replace || replace_all || replace_none || ch == 'n' )
                            {
                                cout << ch << '\n';
                                break;
                            }
                        }
                    }

                    if( !replace )
                    {
                        matched = false;

                        if( is_quieter )
                            cerr << "*** error: file '" << next_file << "' already exists ***" << endl;
                    }
                }

                count = 0;

                if( matched )
                    create_all_directories( create_directories,
                                            directory_perms, destination_directory, list_only, is_quieter );

                if( !matched )
                    ap_ofstream.reset( );
                else if( list_only )
                {
                    ap_ofstream.reset( );
                    cout << next_file << endl;
                }
                else
                {
                    if( !is_quieter )
                        cout << "extracting \"" << next_file << "\"";

                    ap_ofstream = auto_ptr< ofstream >( new ofstream( next_file.c_str( ), ios::out | ios::binary ) );
                    if( !*ap_ofstream.get( ) )
                        throw runtime_error( "unable to open file '" + next_file + "' for output" );
                }
            }
            else if( type == c_type_directory )
            {
                next.erase( 0, 2 );
                pos = next.find( ' ' );
                if( pos == string::npos )
                    throw runtime_error( "unexpected format in line #" + to_string( line ) );

                string::size_type cpos = next.find_last_of( ' ' );
                if( cpos == pos || cpos == string::npos )
                    throw runtime_error( "unexpected format in line #" + to_string( line ) );

                string check( next.substr( cpos + 1 ) );
                next.erase( cpos );

                int next_level( atoi( next.substr( 0, pos ).c_str( ) ) );
                if( next_level > level )
                {
                    if( next_level != level + 1 )
                        throw runtime_error( "expecting level " + to_string( level + 1 )
                                             + " but found " + to_string( next_level ) + " in line #" + to_string( line ) );

                    level = next_level;
                }
                else
                {
                    if( next_level < 0 )
                        throw runtime_error( "invalid level " + to_string( next_level ) + " found in line #" + to_string( line ) );

                    if( !include || create_directories.size( ) > 1 )
                    {
                        size_t test_level( next_level );
                        if( next_level > 0 && !include )
                            --test_level;

                        while( create_directories.size( ) > test_level )
                            create_directories.pop_back( );
                    }

                    level = next_level;

                    while( ( int )paths.size( ) > level )
                        paths.pop( );
                }

                next.erase( 0, pos + 1 );

                pos = next.find( ' ' );
                if( pos == string::npos )
                    throw runtime_error( "unexpected format in line #" + to_string( line ) );

                string rwx_perms( next.substr( 0, pos ) );
                next.erase( 0, pos + 1 );

                string path_name( next );

                if( top_level_directory.empty( ) )
                    top_level_directory = path_name;

                MD5 md5;
                md5.update( ( unsigned char* )rwx_perms.c_str( ), rwx_perms.length( ) );
                md5.update( ( unsigned char* )path_name.c_str( ), path_name.length( ) );
                md5.finalize( );

                auto_ptr< char > ap_digest( md5.hex_digest( ) );

                if( check != string( ap_digest.get( ) ) )
                    cerr << "*** error: directory '" << path_name << "' failed MD5 digest check ***" << endl;

                g_md5.update( ( unsigned char* )ap_digest.get( ), 32 );

                if( include || level > 0 )
                {
                    if( !include )
                    {
                        string::size_type pos = path_name.find( '/' );
                        if( pos == string::npos )
                            throw runtime_error( "unexpected path_name '" + path_name + " found in line #" + to_string( line ) );

                        path_name.erase( 0, pos + 1 );
                    }

                    if( !junk && !created.count( path_name ) )
                    {
                        created.insert( path_name );
                        create_directories.push_back( path_name );
                        directory_perms.insert( make_pair( path_name, rwx_perms ) );

                        if( !prune )
                            create_all_directories( create_directories,
                                                    directory_perms, destination_directory, list_only, is_quieter );
                    }

                    paths.push( path_name );
                }

                is_first = false;
            }
            else if( type == c_type_checksum )
            {
                g_md5.finalize( );
                auto_ptr< char > ap_digest( g_md5.hex_digest( ) );

                next.erase( 0, 2 );

                if( next != string( ap_digest.get( ) ) )
                    cerr << "*** error: bundle file failed MD5 digest check ***" << endl;

                finished = true;
            }
            else
                throw runtime_error( "unexpected entry type '" + to_string( type ) + "' found in line #" + to_string( line ) );
        }

        if( !is_quieter )
        {
            for( size_t i = 0; i < filename_filters.size( ); i++ )
            {
                if( matched_filters.count( filename_filters[ i ] ) == 0 )
                    cout << "warning: found no files matching '" << filename_filters[ i ] << "'" << endl;
            }
        }

        if( !finished )
            cerr << "*** error: final MD5 digest not found (file truncated?) ***" << endl;

#ifdef ZLIB_SUPPORT
        if( use_zlib && !gzeof( gzf ) )
            throw runtime_error( "unexpected error occurred whilst reading '" + filename + "' for input" );
#endif
        if( !use_zlib && !inpf.eof( ) )
            throw runtime_error( "unexpected error occurred whilst reading '" + filename + "' for input" );

        if( !is_quiet && !list_only )
            cout << "==> finished unbundling '" << filename << "'" << endl;
    }
    catch( exception& x )
    {
        cerr << "error: " << x.what( ) << endl;
        return 1;
    }

    return 0;
}