2007-01-11 08:53:08 +01:00
# include "azlib.h"
# include <string.h>
# include <assert.h>
# include <stdio.h>
2007-01-14 04:51:22 +01:00
# include <stdarg.h>
2007-01-26 19:17:53 +01:00
# include <m_ctype.h>
2007-02-21 15:21:14 +01:00
# include <m_string.h>
2007-01-14 04:51:22 +01:00
# include <my_getopt.h>
# include <mysql_version.h>
2007-01-11 08:53:08 +01:00
# define BUFFER_LEN 1024
2007-01-21 02:19:54 +01:00
# define ARCHIVE_ROW_HEADER_SIZE 4
2007-01-11 08:53:08 +01:00
2007-01-14 04:51:22 +01:00
# define SHOW_VERSION "0.1"
static void get_options ( int * argc , char * * * argv ) ;
static void print_version ( void ) ;
static void usage ( void ) ;
static const char * opt_tmpdir ;
2007-01-26 19:17:53 +01:00
static const char * new_auto_increment ;
unsigned long long new_auto_increment_value ;
2007-01-14 04:51:22 +01:00
static const char * load_default_groups [ ] = { " archive_reader " , 0 } ;
static char * * default_argv ;
2007-01-24 19:30:06 +01:00
int opt_check , opt_force , opt_quiet , opt_backup = 0 , opt_extract_frm ;
2007-01-26 19:17:53 +01:00
int opt_autoincrement ;
2007-01-14 04:51:22 +01:00
2007-01-11 08:53:08 +01:00
int main ( int argc , char * argv [ ] )
{
unsigned int ret ;
azio_stream reader_handle ;
MY_INIT ( argv [ 0 ] ) ;
2007-01-14 04:51:22 +01:00
get_options ( & argc , & argv ) ;
2007-01-11 08:53:08 +01:00
2007-01-14 04:51:22 +01:00
if ( argc < 1 )
2007-01-11 08:53:08 +01:00
{
printf ( " No file specified. \n " ) ;
return 0 ;
}
2007-01-14 04:51:22 +01:00
if ( ! ( ret = azopen ( & reader_handle , argv [ 0 ] , O_RDONLY | O_BINARY ) ) )
2007-01-11 08:53:08 +01:00
{
2007-01-14 04:51:22 +01:00
printf ( " Could not open Archive file \n " ) ;
2007-01-11 08:53:08 +01:00
return 0 ;
}
2007-01-26 19:17:53 +01:00
if ( opt_autoincrement )
{
azio_stream writer_handle ;
if ( new_auto_increment_value )
{
if ( reader_handle . auto_increment > = new_auto_increment_value )
{
printf ( " Value is lower then current value \n " ) ;
goto end ;
}
}
else
{
new_auto_increment_value = reader_handle . auto_increment + 1 ;
}
if ( ! ( ret = azopen ( & writer_handle , argv [ 0 ] , O_CREAT | O_RDWR | O_BINARY ) ) )
{
printf ( " Could not open file for update: %s \n " , argv [ 0 ] ) ;
goto end ;
}
writer_handle . auto_increment = new_auto_increment_value ;
azclose ( & writer_handle ) ;
azflush ( & reader_handle , Z_SYNC_FLUSH ) ;
}
2007-01-14 04:51:22 +01:00
printf ( " Version %u \n " , reader_handle . version ) ;
2007-01-13 05:05:55 +01:00
if ( reader_handle . version > 2 )
{
2007-01-21 20:41:00 +01:00
printf ( " \t Minor version %u \n " , reader_handle . minor_version ) ;
printf ( " \t Start position %llu \n " , ( unsigned long long ) reader_handle . start ) ;
2007-01-21 02:19:54 +01:00
printf ( " \t Block size %u \n " , reader_handle . block_size ) ;
printf ( " \t Rows %llu \n " , reader_handle . rows ) ;
printf ( " \t Autoincrement %llu \n " , reader_handle . auto_increment ) ;
printf ( " \t Check Point %llu \n " , reader_handle . check_point ) ;
printf ( " \t Forced Flushes %llu \n " , reader_handle . forced_flushes ) ;
printf ( " \t Longest Row %u \n " , reader_handle . longest_row ) ;
printf ( " \t Shortest Row %u \n " , reader_handle . shortest_row ) ;
printf ( " \t State %s \n " , ( reader_handle . dirty ? " dirty " : " clean " ) ) ;
2007-01-24 19:30:06 +01:00
printf ( " \t FRM stored at %u \n " , reader_handle . frm_start_pos ) ;
printf ( " \t Comment stored at %u \n " , reader_handle . comment_start_pos ) ;
printf ( " \t Data starts at %u \n " , ( unsigned int ) reader_handle . start ) ;
if ( reader_handle . frm_start_pos )
printf ( " \t FRM length %u \n " , reader_handle . frm_length ) ;
if ( reader_handle . comment_start_pos )
{
char * comment =
( char * ) malloc ( sizeof ( char ) * reader_handle . comment_length ) ;
azread_comment ( & reader_handle , comment ) ;
printf ( " \t Comment length %u \n \t \t %.*s \n " , reader_handle . comment_length ,
reader_handle . comment_length , comment ) ;
free ( comment ) ;
}
2007-01-13 05:05:55 +01:00
}
2007-01-21 02:19:54 +01:00
else
{
goto end ;
}
printf ( " \n " ) ;
if ( opt_check )
{
byte size_buffer [ ARCHIVE_ROW_HEADER_SIZE ] ;
int error ;
unsigned int x ;
unsigned int read ;
unsigned int row_len ;
unsigned long long row_count = 0 ;
char buffer ;
while ( ( read = azread ( & reader_handle , ( byte * ) size_buffer ,
ARCHIVE_ROW_HEADER_SIZE , & error ) ) )
{
if ( error = = Z_STREAM_ERROR | | ( read & & read < ARCHIVE_ROW_HEADER_SIZE ) )
{
printf ( " Table is damaged \n " ) ;
goto end ;
}
/* If we read nothing we are at the end of the file */
if ( read = = 0 | | read ! = ARCHIVE_ROW_HEADER_SIZE )
break ;
row_len = uint4korr ( size_buffer ) ;
row_count + + ;
if ( row_len > reader_handle . longest_row )
{
printf ( " Table is damaged, row %llu is invalid \n " ,
row_count ) ;
goto end ;
}
for ( read = x = 0 ; x < row_len ; x + + )
{
read + = ( unsigned int ) azread ( & reader_handle , & buffer , sizeof ( char ) , & error ) ;
if ( ! read )
break ;
}
if ( row_len ! = read )
{
printf ( " Row length did not match row (at %llu). %u != %u \n " ,
row_count , row_len , read ) ;
goto end ;
}
}
if ( 0 )
{
printf ( " Table is damaged \n " ) ;
goto end ;
}
else
{
printf ( " Found %llu rows \n " , row_count ) ;
}
}
if ( opt_backup )
{
byte size_buffer [ ARCHIVE_ROW_HEADER_SIZE ] ;
int error ;
unsigned int read ;
unsigned int row_len ;
unsigned long long row_count = 0 ;
char * buffer ;
azio_stream writer_handle ;
buffer = ( char * ) malloc ( reader_handle . longest_row ) ;
if ( buffer = = NULL )
{
printf ( " Could not allocate memory for row %llu \n " , row_count ) ;
goto end ;
}
if ( ! ( ret = azopen ( & writer_handle , argv [ 1 ] , O_CREAT | O_RDWR | O_BINARY ) ) )
{
printf ( " Could not open file for backup: %s \n " , argv [ 1 ] ) ;
goto end ;
}
writer_handle . auto_increment = reader_handle . auto_increment ;
2007-01-24 19:30:06 +01:00
if ( reader_handle . frm_length )
{
char * ptr ;
ptr = ( char * ) my_malloc ( sizeof ( char ) * reader_handle . frm_length , MYF ( 0 ) ) ;
azread_frm ( & reader_handle , ptr ) ;
azwrite_frm ( & writer_handle , ptr , reader_handle . frm_length ) ;
my_free ( ptr , MYF ( 0 ) ) ;
}
if ( reader_handle . comment_length )
{
char * ptr ;
ptr = ( char * ) my_malloc ( sizeof ( char ) * reader_handle . comment_length , MYF ( 0 ) ) ;
azread_comment ( & reader_handle , ptr ) ;
azwrite_comment ( & writer_handle , ptr , reader_handle . comment_length ) ;
my_free ( ptr , MYF ( 0 ) ) ;
}
2007-01-21 02:19:54 +01:00
while ( ( read = azread ( & reader_handle , ( byte * ) size_buffer ,
ARCHIVE_ROW_HEADER_SIZE , & error ) ) )
{
if ( error = = Z_STREAM_ERROR | | ( read & & read < ARCHIVE_ROW_HEADER_SIZE ) )
{
printf ( " Table is damaged \n " ) ;
goto end ;
}
/* If we read nothing we are at the end of the file */
if ( read = = 0 | | read ! = ARCHIVE_ROW_HEADER_SIZE )
break ;
row_len = uint4korr ( size_buffer ) ;
row_count + + ;
memcpy ( buffer , size_buffer , ARCHIVE_ROW_HEADER_SIZE ) ;
2007-01-11 08:53:08 +01:00
2007-01-21 02:19:54 +01:00
read = ( unsigned int ) azread ( & reader_handle , buffer + ARCHIVE_ROW_HEADER_SIZE ,
row_len , & error ) ;
DBUG_ASSERT ( read = = row_len ) ;
azwrite ( & writer_handle , buffer , row_len + ARCHIVE_ROW_HEADER_SIZE ) ;
if ( row_len ! = read )
{
printf ( " Row length did not match row (at %llu). %u != %u \n " ,
row_count , row_len , read ) ;
goto end ;
}
if ( reader_handle . rows = = writer_handle . rows )
break ;
}
free ( buffer ) ;
azclose ( & writer_handle ) ;
}
2007-01-24 19:30:06 +01:00
if ( opt_extract_frm )
{
File frm_file ;
char * ptr ;
frm_file = my_open ( argv [ 1 ] , O_CREAT | O_RDWR | O_BINARY , MYF ( 0 ) ) ;
ptr = ( char * ) my_malloc ( sizeof ( char ) * reader_handle . frm_length , MYF ( 0 ) ) ;
azread_frm ( & reader_handle , ptr ) ;
my_write ( frm_file , ptr , reader_handle . frm_length , MYF ( 0 ) ) ;
my_close ( frm_file , MYF ( 0 ) ) ;
my_free ( ptr , MYF ( 0 ) ) ;
}
2007-01-21 02:19:54 +01:00
end :
printf ( " \n " ) ;
2007-01-11 08:53:08 +01:00
azclose ( & reader_handle ) ;
return 0 ;
}
2007-01-14 04:51:22 +01:00
static my_bool
get_one_option ( int optid ,
const struct my_option * opt __attribute__ ( ( unused ) ) ,
char * argument )
{
switch ( optid ) {
2007-01-21 02:19:54 +01:00
case ' b ' :
opt_backup = 1 ;
break ;
2007-01-14 04:51:22 +01:00
case ' c ' :
2007-01-21 02:19:54 +01:00
opt_check = 1 ;
2007-01-14 04:51:22 +01:00
break ;
2007-01-24 19:30:06 +01:00
case ' e ' :
opt_extract_frm = 1 ;
break ;
2007-01-14 04:51:22 +01:00
case ' f ' :
2007-01-21 02:19:54 +01:00
opt_force = 1 ;
2007-01-14 04:51:22 +01:00
printf ( " Not implemented yet \n " ) ;
break ;
case ' q ' :
2007-01-21 02:19:54 +01:00
opt_quiet = 1 ;
2007-01-14 04:51:22 +01:00
printf ( " Not implemented yet \n " ) ;
break ;
case ' V ' :
print_version ( ) ;
exit ( 0 ) ;
case ' t ' :
printf ( " Not implemented yet \n " ) ;
break ;
case ' A ' :
2007-01-26 19:17:53 +01:00
opt_autoincrement = 1 ;
if ( argument )
new_auto_increment_value = strtoull ( argument , NULL , 0 ) ;
else
new_auto_increment_value = 0 ;
2007-01-14 04:51:22 +01:00
break ;
case ' ? ' :
usage ( ) ;
exit ( 0 ) ;
case ' # ' :
if ( argument = = disabled_my_option )
{
DBUG_POP ( ) ;
}
else
{
DBUG_PUSH ( argument ? argument : " d:t:o,/tmp/archive_reader.trace " ) ;
}
break ;
}
return 0 ;
}
static struct my_option my_long_options [ ] =
{
2007-01-21 02:19:54 +01:00
{ " backup " , ' b ' ,
" Make a backup of an archive table. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " check " , ' c ' , " Check table for errors. " ,
2007-01-14 04:51:22 +01:00
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
# ifndef DBUG_OFF
{ " debug " , ' # ' ,
" Output debug log. Often this is 'd:t:o,filename'. " ,
0 , 0 , 0 , GET_STR , OPT_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
# endif
2007-01-24 19:30:06 +01:00
{ " extract-frm " , ' e ' ,
" Extract the frm file. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
2007-01-14 04:51:22 +01:00
{ " force " , ' f ' ,
" Restart with -r if there are any errors in the table. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " help " , ' ? ' ,
" Display this help and exit. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " quick " , ' q ' , " Faster repair by not modifying the data file. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " repair " , ' r ' , " Repair a damaged Archive version 3 or above file. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " set-auto-increment " , ' A ' ,
2007-01-26 19:17:53 +01:00
" Force auto_increment to start at this or higher value. If no value is given, then sets the next auto_increment value to the highest used value for the auto key + 1. " ,
( gptr * ) & new_auto_increment ,
( gptr * ) & new_auto_increment ,
2007-01-14 04:51:22 +01:00
0 , GET_ULL , OPT_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " silent " , ' s ' ,
" Only print errors. One can use two -s to make archive_reader very silent. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " tmpdir " , ' t ' ,
" Path for temporary files. " ,
( gptr * ) & opt_tmpdir ,
0 , 0 , GET_STR , REQUIRED_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " version " , ' V ' ,
" Print version and exit. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 }
} ;
static void usage ( void )
{
print_version ( ) ;
puts ( " Copyright (C) 2007 MySQL AB " ) ;
puts ( " This software comes with ABSOLUTELY NO WARRANTY. This is free software, \
\ nand you are welcome to modify and redistribute it under the GPL \
license \ n " );
puts ( " Read and modify Archive files directly \n " ) ;
2007-01-21 02:19:54 +01:00
printf ( " Usage: %s [OPTIONS] file_to_be_looked_at [file_for_backup] \n " , my_progname ) ;
2007-01-14 04:51:22 +01:00
print_defaults ( " my " , load_default_groups ) ;
my_print_help ( my_long_options ) ;
}
static void print_version ( void )
{
printf ( " %s Ver %s Distrib %s, for %s (%s) \n " , my_progname , SHOW_VERSION ,
MYSQL_SERVER_VERSION , SYSTEM_TYPE , MACHINE_TYPE ) ;
}
static void get_options ( int * argc , char * * * argv )
{
load_defaults ( " my " , load_default_groups , argc , argv ) ;
default_argv = * argv ;
handle_options ( argc , argv , my_long_options , get_one_option ) ;
if ( * argc = = 0 )
{
usage ( ) ;
exit ( - 1 ) ;
}
return ;
} /* get options */