Browse Source
Merge 10.1 into 10.2
Merge 10.1 into 10.2
Also, include fixes by Vladislav Vaintroub to the aws_key_management plugin. The AWS C++ SDK specifically depends on OPENSSL_LIBRARIES, not generic SSL_LIBRARIES (such as YaSSL).pull/388/head
217 changed files with 30598 additions and 1664 deletions
-
7.gitignore
-
135client/mysqltest.cc
-
4cmake/build_configurations/mysql_release.cmake
-
7cmake/cpack_rpm.cmake
-
4cmake/plugin.cmake
-
2debian/control
-
2debian/mariadb-backup-10.1.files
-
1debian/mariadb-server-10.2.install
-
214extra/mariabackup/CMakeLists.txt
-
2075extra/mariabackup/backup_copy.cc
-
49extra/mariabackup/backup_copy.h
-
1648extra/mariabackup/backup_mysql.cc
-
92extra/mariabackup/backup_mysql.h
-
1018extra/mariabackup/changed_page_bitmap.cc
-
85extra/mariabackup/changed_page_bitmap.h
-
174extra/mariabackup/common.h
-
33extra/mariabackup/crc/CMakeLists.txt
-
21extra/mariabackup/crc/config.h.cmake
-
511extra/mariabackup/crc/crc-intel-pclmul.c
-
25extra/mariabackup/crc/crc-intel-pclmul.h
-
72extra/mariabackup/crc/crc_glue.c
-
31extra/mariabackup/crc/crc_glue.h
-
137extra/mariabackup/datasink.c
-
100extra/mariabackup/datasink.h
-
280extra/mariabackup/ds_archive.c
-
28extra/mariabackup/ds_archive.h
-
189extra/mariabackup/ds_buffer.c
-
39extra/mariabackup/ds_buffer.h
-
462extra/mariabackup/ds_compress.c
-
28extra/mariabackup/ds_compress.h
-
665extra/mariabackup/ds_decrypt.c
-
30extra/mariabackup/ds_decrypt.h
-
446extra/mariabackup/ds_encrypt.c
-
33extra/mariabackup/ds_encrypt.h
-
151extra/mariabackup/ds_local.c
-
28extra/mariabackup/ds_local.h
-
121extra/mariabackup/ds_stdout.c
-
28extra/mariabackup/ds_stdout.h
-
247extra/mariabackup/ds_tmpfile.c
-
30extra/mariabackup/ds_tmpfile.h
-
223extra/mariabackup/ds_xbstream.c
-
28extra/mariabackup/ds_xbstream.h
-
157extra/mariabackup/encryption_plugin.cc
-
7extra/mariabackup/encryption_plugin.h
-
409extra/mariabackup/fil_cur.cc
-
123extra/mariabackup/fil_cur.h
-
1132extra/mariabackup/innobackupex.cc
-
45extra/mariabackup/innobackupex.h
-
848extra/mariabackup/quicklz/quicklz.c
-
144extra/mariabackup/quicklz/quicklz.h
-
206extra/mariabackup/read_filt.cc
-
62extra/mariabackup/read_filt.h
-
219extra/mariabackup/write_filt.cc
-
58extra/mariabackup/write_filt.h
-
220extra/mariabackup/wsrep.cc
-
32extra/mariabackup/wsrep.h
-
78extra/mariabackup/xb0xb.h
-
48extra/mariabackup/xb_regex.h
-
2721extra/mariabackup/xbcloud.cc
-
696extra/mariabackup/xbcrypt.c
-
79extra/mariabackup/xbcrypt.h
-
328extra/mariabackup/xbcrypt_common.c
-
64extra/mariabackup/xbcrypt_common.h
-
252extra/mariabackup/xbcrypt_read.c
-
105extra/mariabackup/xbcrypt_write.c
-
613extra/mariabackup/xbstream.c
-
107extra/mariabackup/xbstream.h
-
228extra/mariabackup/xbstream_read.c
-
294extra/mariabackup/xbstream_write.c
-
7498extra/mariabackup/xtrabackup.cc
-
247extra/mariabackup/xtrabackup.h
-
71include/my_crypt.h
-
20include/my_pthread.h
-
23include/my_sys.h
-
2include/mysql/plugin.h
-
37include/mysql/plugin_audit.h.pp
-
37include/mysql/plugin_auth.h.pp
-
37include/mysql/plugin_encryption.h.pp
-
37include/mysql/plugin_ftparser.h.pp
-
37include/mysql/plugin_password_validation.h.pp
-
120include/mysql/service_my_crypt.h
-
64include/mysql/service_my_print_error.h
-
2include/mysql/services.h
-
2include/service_versions.h
-
4libservices/CMakeLists.txt
-
2libservices/my_crypt_service.c
-
17libservices/my_print_error_service.c
-
6mysql-test/include/default_client.cnf
-
4mysql-test/include/default_mysqld.cnf
-
3mysql-test/include/write_var_to_file.inc
-
56mysql-test/lib/My/ConfigFactory.pm
-
21mysql-test/lib/generate-ssl-certs.sh
-
1mysql-test/mysql-test-run.pl
-
2mysql-test/r/handlersocket.result
-
132mysql-test/r/mysql_plugin.result
-
6mysql-test/r/plugin.result
-
4mysql-test/r/ssl.result
-
115mysql-test/std_data/cacert.pem
-
28mysql-test/std_data/cakey.pem
-
90mysql-test/std_data/client-cert.pem
@ -0,0 +1,2 @@ |
|||
usr/bin/mariabackup |
|||
usr/bin/mbstream |
@ -0,0 +1,214 @@ |
|||
# Copyright (c) 2013, 2017 Percona LLC and/or its affiliates. |
|||
# |
|||
# This program is free software; you can redistribute it and/or modify |
|||
# it under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; version 2 of the License. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License |
|||
# along with this program; if not, write to the Free Software |
|||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
|
|||
OPTION(WITH_MARIABACKUP "Include mariabackup" ON) |
|||
IF(NOT WITH_MARIABACKUP) |
|||
RETURN() |
|||
ENDIF() |
|||
|
|||
|
|||
IF(NOT WIN32) |
|||
CHECK_SYMBOL_EXISTS(regcomp regex.h HAVE_SYSTEM_REGEX) |
|||
IF(HAVE_SYSTEM_REGEX) |
|||
ADD_DEFINITIONS(-DHAVE_SYSTEM_REGEX) |
|||
ENDIF() |
|||
ENDIF() |
|||
|
|||
IF(WITH_LIBARCHIVE STREQUAL "STATIC") |
|||
SET(CMAKE_FIND_LIBRARY_SUFFIXES .a .lib) |
|||
ENDIF() |
|||
|
|||
FIND_PACKAGE(LibArchive) |
|||
|
|||
IF(NOT DEFINED WITH_LIBARCHIVE) |
|||
IF(LibArchive_FOUND) |
|||
SET(WITH_LIBARCHIVE_DEFAULT ON) |
|||
ELSE() |
|||
SET(WITH_LIBARCHIVE_DEFAULT OFF) |
|||
ENDIF() |
|||
SET(WITH_LIBARCHIVE ${WITH_LIBARCHIVE_DEFAULT} CACHE STRING "Use libarchive for streaming features (ON, OFF or STATIC)" ) |
|||
ENDIF() |
|||
|
|||
IF(NOT WITH_LIBARCHIVE MATCHES "^(ON|OFF|STATIC)$") |
|||
MESSAGE(FATAL_ERROR "Invalid value for WITH_LIBARCHIVE: '${WITH_LIBARCHIVE}'. Use one of ON, OFF or STATIC") |
|||
ENDIF() |
|||
|
|||
IF(UNIX) |
|||
SET(PIC_FLAG -fPIC) |
|||
ENDIF() |
|||
|
|||
IF((NOT WITH_LIBARCHIVE STREQUAL "OFF") AND (NOT LibArchive_FOUND)) |
|||
IF(CMAKE_VERSION VERSION_LESS "2.8.12") |
|||
MESSAGE("libarchive can't be built, old cmake") |
|||
ELSE() |
|||
# Build a local version |
|||
INCLUDE(ExternalProject) |
|||
SET(LIBARCHIVE_DIR ${CMAKE_CURRENT_BINARY_DIR}/libarchive) |
|||
SET(libarchive_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libarchive) |
|||
SET(libarchive_CMAKE_ARGS |
|||
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> |
|||
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} |
|||
-DENABLE_ICONV=OFF |
|||
-DENABLE_TAR=ON |
|||
-DENABLE_OPENSSL=OFF |
|||
-DENABLE_TEST=OFF |
|||
"-DCMAKE_C_FLAGS_DEBUG=${CMAKE_C_FLAGS_DEBUG} ${PIC_FLAG}" |
|||
"-DCMAKE_C_FLAGS_RELWITHDEBINFO=${CMAKE_C_FLAGS_RELWITHDEBINFO} ${PIC_FLAG}" |
|||
"-DCMAKE_C_FLAGS_RELEASE=${CMAKE_C_FLAGS_RELEASE} ${PIC_FLAG}" |
|||
"-DCMAKE_C_FLAGS_MINSIZEREL=${CMAKE_C_FLAGS_MINSIZEREL} ${PIC_FLAG}" |
|||
) |
|||
IF(WIN32) |
|||
SET(libarchive_CMAKE_ARGS ${libarchive_CMAKE_ARGS} -DWINDOWS_VERSION=WIN7 -DCMAKE_DEBUG_POSTFIX=d) |
|||
SET(LIBARCHIVE_RELEASE_LIB ${LIBARCHIVE_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}archive_static${CMAKE_STATIC_LIBRARY_SUFFIX}) |
|||
SET(LIBARCHIVE_DEBUG_LIB ${LIBARCHIVE_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}archive_staticd${CMAKE_STATIC_LIBRARY_SUFFIX}) |
|||
SET(byproducts ${LIBARCHIVE_RELEASE_LIB} ${LIBARCHIVE_DEBUG_LIB}) |
|||
ELSE() |
|||
SET(LIBARCHIVE_LIB ${LIBARCHIVE_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}archive${CMAKE_STATIC_LIBRARY_SUFFIX}) |
|||
SET(byproducts ${LIBARCHIVE_LIB}) |
|||
ENDIF() |
|||
|
|||
IF(CMAKE_VERSION VERSION_GREATER "3.1") |
|||
SET(byproducts BUILD_BYPRODUCTS ${byproducts}) |
|||
ENDIF() |
|||
|
|||
ExternalProject_Add(libarchive |
|||
PREFIX ${libarchive_PREFIX} |
|||
DOWNLOAD_DIR ${LIBARCHIVE_DIR} |
|||
URL http://www.libarchive.org/downloads/libarchive-3.2.2.tar.gz |
|||
INSTALL_DIR ${LIBARCHIVE_DIR} |
|||
CMAKE_ARGS ${libarchive_CMAKE_ARGS} |
|||
${byproducts} |
|||
) |
|||
ADD_LIBRARY(archive_static STATIC IMPORTED) |
|||
ADD_DEPENDENCIES(archive_static libarchive) |
|||
IF(WIN32) |
|||
SET_PROPERTY(TARGET archive_static PROPERTY IMPORTED_LOCATION_RELWITHDEBINFO ${LIBARCHIVE_RELEASE_LIB}) |
|||
SET_PROPERTY(TARGET archive_static PROPERTY IMPORTED_LOCATION_RELEASE ${LIBARCHIVE_RELEASE_LIB}) |
|||
SET_PROPERTY(TARGET archive_static PROPERTY IMPORTED_LOCATION_DEBUG ${LIBARCHIVE_DEBUG_LIB}) |
|||
SET_PROPERTY(TARGET archive_static PROPERTY IMPORTED_LOCATION_MINSIZEREL ${LIBARCHIVE_RELEASE_LIB}) |
|||
ELSE() |
|||
SET_PROPERTY(TARGET archive_static PROPERTY IMPORTED_LOCATION ${LIBARCHIVE_LIB}) |
|||
ENDIF() |
|||
|
|||
SET(LibArchive_FOUND ON ) |
|||
SET(LibArchive_INCLUDE_DIRS ${LIBARCHIVE_DIR}/include ) |
|||
SET(LibArchive_LIBRARIES archive_static) |
|||
IF(WIN32) |
|||
SET(LIBARCHIVE_STATIC 1) |
|||
ENDIF() |
|||
ENDIF() |
|||
ENDIF() |
|||
|
|||
|
|||
IF(WITH_LIBARCHIVE AND LibArchive_FOUND) |
|||
ADD_DEFINITIONS(-DHAVE_LIBARCHIVE) |
|||
IF(LIBARCHIVE_STATIC) |
|||
ADD_DEFINITIONS(-DLIBARCHIVE_STATIC) |
|||
ENDIF() |
|||
INCLUDE_DIRECTORIES(${LibArchive_INCLUDE_DIRS}) |
|||
LINK_LIBRARIES(${LibArchive_LIBRARIES}) |
|||
SET(DS_ARCHIVE_SOURCE ds_archive.c) |
|||
ENDIF() |
|||
|
|||
INCLUDE_DIRECTORIES( |
|||
${CMAKE_SOURCE_DIR}/include |
|||
${CMAKE_SOURCE_DIR}/storage/xtradb/include |
|||
${CMAKE_SOURCE_DIR}/sql |
|||
${CMAKE_CURRENT_SOURCE_DIR}/quicklz |
|||
${CMAKE_CURRENT_SOURCE_DIR} |
|||
${CMAKE_CURRENT_SOURCE_DIR}/crc |
|||
) |
|||
|
|||
IF(NOT HAVE_SYSTEM_REGEX) |
|||
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/pcre) |
|||
ENDIF() |
|||
|
|||
ADD_DEFINITIONS(-UMYSQL_SERVER) |
|||
######################################################################## |
|||
# xtrabackup binary |
|||
######################################################################## |
|||
|
|||
IF(WIN32) |
|||
SET(NT_SERVICE_SOURCE ${PROJECT_SOURCE_DIR}/sql/nt_servc.cc) |
|||
ELSE() |
|||
SET(NT_SERVICE_SOURCE) |
|||
ENDIF() |
|||
|
|||
ADD_DEFINITIONS(-DPCRE_STATIC=1) |
|||
|
|||
MYSQL_ADD_EXECUTABLE(mariabackup |
|||
xtrabackup.cc |
|||
innobackupex.cc |
|||
changed_page_bitmap.cc |
|||
datasink.c |
|||
${DS_ARCHIVE_SOURCE} |
|||
ds_buffer.c |
|||
ds_compress.c |
|||
ds_local.c |
|||
ds_stdout.c |
|||
ds_tmpfile.c |
|||
ds_xbstream.c |
|||
fil_cur.cc |
|||
quicklz/quicklz.c |
|||
read_filt.cc |
|||
write_filt.cc |
|||
wsrep.cc |
|||
xbstream_write.c |
|||
backup_mysql.cc |
|||
backup_copy.cc |
|||
encryption_plugin.cc |
|||
${PROJECT_SOURCE_DIR}/libmysql/libmysql.c |
|||
${PROJECT_SOURCE_DIR}/sql/net_serv.cc |
|||
${NT_SERVICE_SOURCE} |
|||
COMPONENT backup |
|||
) |
|||
|
|||
|
|||
# Export all symbols on Unix, for better crash callstacks |
|||
SET_TARGET_PROPERTIES(mariabackup PROPERTIES ENABLE_EXPORTS TRUE) |
|||
ADD_SUBDIRECTORY(crc) |
|||
|
|||
|
|||
TARGET_LINK_LIBRARIES(mariabackup sql crc) |
|||
|
|||
IF(NOT HAVE_SYSTEM_REGEX) |
|||
TARGET_LINK_LIBRARIES(mariabackup pcreposix) |
|||
ENDIF() |
|||
|
|||
|
|||
######################################################################## |
|||
# xbstream binary |
|||
######################################################################## |
|||
MYSQL_ADD_EXECUTABLE(mbstream |
|||
ds_buffer.c |
|||
ds_local.c |
|||
ds_stdout.c |
|||
datasink.c |
|||
xbstream.c |
|||
xbstream_read.c |
|||
xbstream_write.c |
|||
COMPONENT backup |
|||
) |
|||
|
|||
|
|||
TARGET_LINK_LIBRARIES(mbstream |
|||
mysys |
|||
crc |
|||
) |
|||
|
|||
IF(MSVC) |
|||
SET_TARGET_PROPERTIES(mbstream PROPERTIES LINK_FLAGS setargv.obj) |
|||
ENDIF() |
2075
extra/mariabackup/backup_copy.cc
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,49 @@ |
|||
|
|||
#ifndef XTRABACKUP_BACKUP_COPY_H |
|||
#define XTRABACKUP_BACKUP_COPY_H |
|||
|
|||
#include <my_global.h> |
|||
#include "datasink.h" |
|||
|
|||
/* special files */ |
|||
#define XTRABACKUP_SLAVE_INFO "xtrabackup_slave_info" |
|||
#define XTRABACKUP_GALERA_INFO "xtrabackup_galera_info" |
|||
#define XTRABACKUP_BINLOG_INFO "xtrabackup_binlog_info" |
|||
#define XTRABACKUP_INFO "xtrabackup_info" |
|||
|
|||
extern bool binlog_locked; |
|||
|
|||
bool |
|||
backup_file_printf(const char *filename, const char *fmt, ...) |
|||
ATTRIBUTE_FORMAT(printf, 2, 0); |
|||
|
|||
/************************************************************************ |
|||
Return true if first and second arguments are the same path. */ |
|||
bool |
|||
equal_paths(const char *first, const char *second); |
|||
|
|||
/************************************************************************ |
|||
Copy file for backup/restore. |
|||
@return true in case of success. */ |
|||
bool |
|||
copy_file(ds_ctxt_t *datasink, |
|||
const char *src_file_path, |
|||
const char *dst_file_path, |
|||
uint thread_n); |
|||
|
|||
bool |
|||
backup_start(); |
|||
bool |
|||
backup_finish(); |
|||
bool |
|||
apply_log_finish(); |
|||
bool |
|||
copy_back(); |
|||
bool |
|||
decrypt_decompress(); |
|||
bool |
|||
is_path_separator(char); |
|||
bool |
|||
directory_exists(const char *dir, bool create); |
|||
|
|||
#endif |
1648
extra/mariabackup/backup_mysql.cc
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,92 @@ |
|||
#ifndef XTRABACKUP_BACKUP_MYSQL_H |
|||
#define XTRABACKUP_BACKUP_MYSQL_H |
|||
|
|||
#include <mysql.h> |
|||
|
|||
/* mysql flavor and version */ |
|||
enum mysql_flavor_t { FLAVOR_UNKNOWN, FLAVOR_MYSQL, |
|||
FLAVOR_PERCONA_SERVER, FLAVOR_MARIADB }; |
|||
extern mysql_flavor_t server_flavor; |
|||
extern unsigned long mysql_server_version; |
|||
|
|||
/* server capabilities */ |
|||
extern bool have_changed_page_bitmaps; |
|||
extern bool have_backup_locks; |
|||
extern bool have_lock_wait_timeout; |
|||
extern bool have_galera_enabled; |
|||
extern bool have_flush_engine_logs; |
|||
extern bool have_multi_threaded_slave; |
|||
extern bool have_gtid_slave; |
|||
|
|||
|
|||
/* History on server */ |
|||
extern time_t history_start_time; |
|||
extern time_t history_end_time; |
|||
extern time_t history_lock_time; |
|||
|
|||
|
|||
extern bool sql_thread_started; |
|||
extern char *mysql_slave_position; |
|||
extern char *mysql_binlog_position; |
|||
extern char *buffer_pool_filename; |
|||
|
|||
/** connection to mysql server */ |
|||
extern MYSQL *mysql_connection; |
|||
|
|||
void |
|||
capture_tool_command(int argc, char **argv); |
|||
|
|||
bool |
|||
select_history(); |
|||
|
|||
bool |
|||
flush_changed_page_bitmaps(); |
|||
|
|||
void |
|||
backup_cleanup(); |
|||
|
|||
bool |
|||
get_mysql_vars(MYSQL *connection); |
|||
|
|||
bool |
|||
detect_mysql_capabilities_for_backup(); |
|||
|
|||
MYSQL * |
|||
xb_mysql_connect(); |
|||
|
|||
MYSQL_RES * |
|||
xb_mysql_query(MYSQL *connection, const char *query, bool use_result, |
|||
bool die_on_error = true); |
|||
|
|||
void |
|||
unlock_all(MYSQL *connection); |
|||
|
|||
bool |
|||
write_current_binlog_file(MYSQL *connection); |
|||
|
|||
bool |
|||
write_binlog_info(MYSQL *connection); |
|||
|
|||
bool |
|||
write_xtrabackup_info(MYSQL *connection); |
|||
|
|||
bool |
|||
write_backup_config_file(); |
|||
|
|||
bool |
|||
lock_binlog_maybe(MYSQL *connection); |
|||
|
|||
bool |
|||
lock_tables(MYSQL *connection); |
|||
|
|||
bool |
|||
wait_for_safe_slave(MYSQL *connection); |
|||
|
|||
bool |
|||
write_galera_info(MYSQL *connection); |
|||
|
|||
bool |
|||
write_slave_info(MYSQL *connection); |
|||
|
|||
|
|||
#endif |
1018
extra/mariabackup/changed_page_bitmap.cc
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,85 @@ |
|||
/****************************************************** |
|||
XtraBackup: hot backup tool for InnoDB |
|||
(c) 2009-2012 Percona Inc. |
|||
Originally Created 3/3/2009 Yasufumi Kinoshita |
|||
Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko, |
|||
Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
/* Changed page bitmap interface */ |
|||
|
|||
#ifndef XB_CHANGED_PAGE_BITMAP_H |
|||
#define XB_CHANGED_PAGE_BITMAP_H |
|||
|
|||
#include <ut0rbt.h> |
|||
#include <fil0fil.h> |
|||
|
|||
/* The changed page bitmap structure */ |
|||
typedef ib_rbt_t xb_page_bitmap; |
|||
|
|||
struct xb_page_bitmap_range_struct; |
|||
|
|||
/* The bitmap range iterator over one space id */ |
|||
typedef struct xb_page_bitmap_range_struct xb_page_bitmap_range; |
|||
|
|||
/****************************************************************//** |
|||
Read the disk bitmap and build the changed page bitmap tree for the |
|||
LSN interval incremental_lsn to checkpoint_lsn_start. |
|||
|
|||
@return the built bitmap tree */ |
|||
xb_page_bitmap* |
|||
xb_page_bitmap_init(void); |
|||
/*=====================*/ |
|||
|
|||
/****************************************************************//** |
|||
Free the bitmap tree. */ |
|||
void |
|||
xb_page_bitmap_deinit( |
|||
/*==================*/ |
|||
xb_page_bitmap* bitmap); /*!<in/out: bitmap tree */ |
|||
|
|||
|
|||
/****************************************************************//** |
|||
Set up a new bitmap range iterator over a given space id changed |
|||
pages in a given bitmap. |
|||
|
|||
@return bitmap range iterator */ |
|||
xb_page_bitmap_range* |
|||
xb_page_bitmap_range_init( |
|||
/*======================*/ |
|||
xb_page_bitmap* bitmap, /*!< in: bitmap to iterate over */ |
|||
ulint space_id); /*!< in: space id */ |
|||
|
|||
/****************************************************************//** |
|||
Get the next page id that has its bit set or cleared, i.e. equal to |
|||
bit_value. |
|||
|
|||
@return page id */ |
|||
ulint |
|||
xb_page_bitmap_range_get_next_bit( |
|||
/*==============================*/ |
|||
xb_page_bitmap_range* bitmap_range, /*!< in/out: bitmap range */ |
|||
ibool bit_value); /*!< in: bit value */ |
|||
|
|||
/****************************************************************//** |
|||
Free the bitmap range iterator. */ |
|||
void |
|||
xb_page_bitmap_range_deinit( |
|||
/*========================*/ |
|||
xb_page_bitmap_range* bitmap_range); /*! in/out: bitmap range */ |
|||
|
|||
#endif |
@ -0,0 +1,174 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2011-2013 Percona LLC and/or its affiliates. |
|||
|
|||
Common declarations for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef XB_COMMON_H |
|||
#define XB_COMMON_H |
|||
|
|||
#include <my_global.h> |
|||
#include <mysql_version.h> |
|||
#include <fcntl.h> |
|||
#include <stdarg.h> |
|||
|
|||
|
|||
# define fil_is_user_tablespace_id(i) ((i) > srv_undo_tablespaces_open) |
|||
|
|||
#ifdef _MSC_VER |
|||
#define stat _stati64 |
|||
#define PATH_MAX MAX_PATH |
|||
#endif |
|||
|
|||
#ifndef HAVE_VASPRINTF |
|||
static inline int vasprintf(char **strp, const char *fmt, va_list args) |
|||
{ |
|||
int len; |
|||
#ifdef _MSC_VER |
|||
len = _vscprintf(fmt, args); |
|||
#else |
|||
len = vsnprintf(NULL, 0, fmt, args); |
|||
#endif |
|||
if (len < 0) |
|||
{ |
|||
return -1; |
|||
} |
|||
*strp = (char *)malloc(len + 1); |
|||
if (!*strp) |
|||
{ |
|||
return -1; |
|||
} |
|||
vsprintf(*strp, fmt, args); |
|||
return len; |
|||
} |
|||
|
|||
static inline int asprintf(char **strp, const char *fmt,...) |
|||
{ |
|||
va_list args; |
|||
va_start(args, fmt); |
|||
int len = vasprintf(strp, fmt, args); |
|||
va_end(args); |
|||
return len; |
|||
} |
|||
#endif |
|||
|
|||
#define xb_a(expr) \ |
|||
do { \ |
|||
if (!(expr)) { \ |
|||
msg("Assertion \"%s\" failed at %s:%lu\n", \ |
|||
#expr, __FILE__, (ulong) __LINE__); \ |
|||
abort(); \ |
|||
} \ |
|||
} while (0); |
|||
|
|||
#ifdef XB_DEBUG |
|||
#define xb_ad(expr) xb_a(expr) |
|||
#else |
|||
#define xb_ad(expr) |
|||
#endif |
|||
|
|||
#define XB_DELTA_INFO_SUFFIX ".meta" |
|||
|
|||
static inline int msg(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2); |
|||
static inline int msg(const char *fmt, ...) |
|||
{ |
|||
int result; |
|||
va_list args; |
|||
|
|||
va_start(args, fmt); |
|||
result = vfprintf(stderr, fmt, args); |
|||
va_end(args); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
static inline int msg_ts(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2); |
|||
static inline int msg_ts(const char *fmt, ...) |
|||
{ |
|||
int result; |
|||
time_t t = time(NULL); |
|||
char date[100]; |
|||
char *line; |
|||
va_list args; |
|||
|
|||
strftime(date, sizeof(date), "%y%m%d %H:%M:%S", localtime(&t)); |
|||
|
|||
va_start(args, fmt); |
|||
result = vasprintf(&line, fmt, args); |
|||
va_end(args); |
|||
|
|||
if (result != -1) { |
|||
result = fprintf(stderr, "%s %s", date, line); |
|||
free(line); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
/* Use POSIX_FADV_NORMAL when available */ |
|||
|
|||
#ifdef POSIX_FADV_NORMAL |
|||
# define USE_POSIX_FADVISE |
|||
#else |
|||
# define POSIX_FADV_NORMAL |
|||
# define POSIX_FADV_SEQUENTIAL |
|||
# define POSIX_FADV_DONTNEED |
|||
# define posix_fadvise(a,b,c,d) do {} while(0) |
|||
#endif |
|||
|
|||
/*********************************************************************** |
|||
Computes bit shift for a given value. If the argument is not a power |
|||
of 2, returns 0.*/ |
|||
static inline size_t |
|||
get_bit_shift(size_t value) |
|||
{ |
|||
size_t shift; |
|||
|
|||
if (value == 0) |
|||
return 0; |
|||
|
|||
for (shift = 0; !(value & 1); shift++) { |
|||
value >>= 1; |
|||
} |
|||
return (value >> 1) ? 0 : shift; |
|||
} |
|||
|
|||
/**************************************************************************** |
|||
Read 'len' bytes from 'fd'. It is identical to my_read(..., MYF(MY_FULL_IO)), |
|||
i.e. tries to combine partial reads into a single block of size 'len', except |
|||
that it bails out on EOF or error, and returns the number of successfully read |
|||
bytes instead. */ |
|||
static inline size_t |
|||
xb_read_full(File fd, uchar *buf, size_t len) |
|||
{ |
|||
size_t tlen = 0; |
|||
size_t tbytes; |
|||
|
|||
while (tlen < len) { |
|||
tbytes = my_read(fd, buf, len - tlen, MYF(MY_WME)); |
|||
if (tbytes == 0 || tbytes == MY_FILE_ERROR) { |
|||
break; |
|||
} |
|||
|
|||
buf += tbytes; |
|||
tlen += tbytes; |
|||
} |
|||
|
|||
return tlen; |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,33 @@ |
|||
# Copyright (c) 2017 Percona LLC and/or its affiliates. |
|||
# |
|||
# This program is free software; you can redistribute it and/or modify |
|||
# it under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; version 2 of the License. |
|||
|
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
|
|||
# You should have received a copy of the GNU General Public License |
|||
# along with this program; if not, write to the Free Software |
|||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
PROJECT(crc C) |
|||
|
|||
IF(NOT CMAKE_CROSSCOMPILING AND NOT MSVC) |
|||
STRING(TOLOWER ${CMAKE_SYSTEM_PROCESSOR} processor) |
|||
IF(processor MATCHES "86" OR processor MATCHES "amd64" OR processor MATCHES "x64") |
|||
# Check for PCLMUL instruction |
|||
CHECK_C_SOURCE_RUNS(" |
|||
int main() |
|||
{ |
|||
asm volatile (\"pclmulqdq \\$0x00, %%xmm1, %%xmm0\":::\"cc\"); |
|||
return 0; |
|||
}" HAVE_CLMUL_INSTRUCTION) |
|||
ENDIF() |
|||
ENDIF() |
|||
IF(HAVE_CLMUL_INSTRUCTION) |
|||
ADD_DEFINITIONS(-DHAVE_CLMUL_INSTRUCTION) |
|||
ENDIF() |
|||
ADD_LIBRARY(crc crc_glue.c crc-intel-pclmul.c) |
@ -0,0 +1,21 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2017 Percona LLC and/or its affiliates. |
|||
|
|||
Zlib compatible CRC-32 implementation. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#cmakedefine HAVE_CLMUL_INSTRUCTION 1 |
@ -0,0 +1,511 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2017 Percona LLC and/or its affiliates. |
|||
|
|||
CRC32 using Intel's PCLMUL instruction. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
/* crc-intel-pclmul.c - Intel PCLMUL accelerated CRC implementation |
|||
* Copyright (C) 2016 Jussi Kivilinna <jussi.kivilinna@iki.fi> |
|||
* |
|||
* This file is part of Libgcrypt. |
|||
* |
|||
* Libgcrypt is free software; you can redistribute it and/or modify |
|||
* it under the terms of the GNU Lesser General Public License as |
|||
* published by the Free Software Foundation; either version 2.1 of |
|||
* the License, or (at your option) any later version. |
|||
* |
|||
* Libgcrypt is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Lesser General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Lesser General Public |
|||
* License along with this program; if not, write to the Free Software |
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
|||
* |
|||
*/ |
|||
|
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <stdint.h> |
|||
|
|||
# define U64_C(c) (c ## UL) |
|||
|
|||
typedef uint32_t u32; |
|||
typedef uint16_t u16; |
|||
typedef uint64_t u64; |
|||
#ifndef byte |
|||
typedef uint8_t byte; |
|||
#endif |
|||
|
|||
# define _gcry_bswap32 __builtin_bswap32 |
|||
|
|||
#if __GNUC__ >= 4 && defined(__x86_64__) && defined(HAVE_CLMUL_INSTRUCTION) |
|||
|
|||
#if _GCRY_GCC_VERSION >= 40400 /* 4.4 */ |
|||
/* Prevent compiler from issuing SSE instructions between asm blocks. */ |
|||
# pragma GCC target("no-sse") |
|||
#endif |
|||
|
|||
|
|||
#define ALIGNED_16 __attribute__ ((aligned (16))) |
|||
|
|||
|
|||
struct u16_unaligned_s |
|||
{ |
|||
u16 a; |
|||
} __attribute__((packed, aligned (1), may_alias)); |
|||
|
|||
|
|||
/* Constants structure for generic reflected/non-reflected CRC32 CLMUL |
|||
* functions. */ |
|||
struct crc32_consts_s |
|||
{ |
|||
/* k: { x^(32*17), x^(32*15), x^(32*5), x^(32*3), x^(32*2), 0 } mod P(x) */ |
|||
u64 k[6]; |
|||
/* my_p: { floor(x^64 / P(x)), P(x) } */ |
|||
u64 my_p[2]; |
|||
}; |
|||
|
|||
|
|||
/* CLMUL constants for CRC32 and CRC32RFC1510. */ |
|||
static const struct crc32_consts_s crc32_consts ALIGNED_16 = |
|||
{ |
|||
{ /* k[6] = reverse_33bits( x^(32*y) mod P(x) ) */ |
|||
U64_C(0x154442bd4), U64_C(0x1c6e41596), /* y = { 17, 15 } */ |
|||
U64_C(0x1751997d0), U64_C(0x0ccaa009e), /* y = { 5, 3 } */ |
|||
U64_C(0x163cd6124), 0 /* y = 2 */ |
|||
}, |
|||
{ /* my_p[2] = reverse_33bits ( { floor(x^64 / P(x)), P(x) } ) */ |
|||
U64_C(0x1f7011641), U64_C(0x1db710641) |
|||
} |
|||
}; |
|||
|
|||
/* Common constants for CRC32 algorithms. */ |
|||
static const byte crc32_refl_shuf_shift[3 * 16] ALIGNED_16 = |
|||
{ |
|||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
|||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, |
|||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
}; |
|||
static const byte crc32_partial_fold_input_mask[16 + 16] ALIGNED_16 = |
|||
{ |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
}; |
|||
static const u64 crc32_merge9to15_shuf[15 - 9 + 1][2] ALIGNED_16 = |
|||
{ |
|||
{ U64_C(0x0706050403020100), U64_C(0xffffffffffffff0f) }, /* 9 */ |
|||
{ U64_C(0x0706050403020100), U64_C(0xffffffffffff0f0e) }, |
|||
{ U64_C(0x0706050403020100), U64_C(0xffffffffff0f0e0d) }, |
|||
{ U64_C(0x0706050403020100), U64_C(0xffffffff0f0e0d0c) }, |
|||
{ U64_C(0x0706050403020100), U64_C(0xffffff0f0e0d0c0b) }, |
|||
{ U64_C(0x0706050403020100), U64_C(0xffff0f0e0d0c0b0a) }, |
|||
{ U64_C(0x0706050403020100), U64_C(0xff0f0e0d0c0b0a09) }, /* 15 */ |
|||
}; |
|||
static const u64 crc32_merge5to7_shuf[7 - 5 + 1][2] ALIGNED_16 = |
|||
{ |
|||
{ U64_C(0xffffff0703020100), U64_C(0xffffffffffffffff) }, /* 5 */ |
|||
{ U64_C(0xffff070603020100), U64_C(0xffffffffffffffff) }, |
|||
{ U64_C(0xff07060503020100), U64_C(0xffffffffffffffff) }, /* 7 */ |
|||
}; |
|||
|
|||
/* PCLMUL functions for reflected CRC32. */ |
|||
static inline void |
|||
crc32_reflected_bulk (u32 *pcrc, const byte *inbuf, size_t inlen, |
|||
const struct crc32_consts_s *consts) |
|||
{ |
|||
if (inlen >= 8 * 16) |
|||
{ |
|||
asm volatile ("movd %[crc], %%xmm4\n\t" |
|||
"movdqu %[inbuf_0], %%xmm0\n\t" |
|||
"movdqu %[inbuf_1], %%xmm1\n\t" |
|||
"movdqu %[inbuf_2], %%xmm2\n\t" |
|||
"movdqu %[inbuf_3], %%xmm3\n\t" |
|||
"pxor %%xmm4, %%xmm0\n\t" |
|||
: |
|||
: [inbuf_0] "m" (inbuf[0 * 16]), |
|||
[inbuf_1] "m" (inbuf[1 * 16]), |
|||
[inbuf_2] "m" (inbuf[2 * 16]), |
|||
[inbuf_3] "m" (inbuf[3 * 16]), |
|||
[crc] "m" (*pcrc) |
|||
); |
|||
|
|||
inbuf += 4 * 16; |
|||
inlen -= 4 * 16; |
|||
|
|||
asm volatile ("movdqa %[k1k2], %%xmm4\n\t" |
|||
: |
|||
: [k1k2] "m" (consts->k[1 - 1]) |
|||
); |
|||
|
|||
/* Fold by 4. */ |
|||
while (inlen >= 4 * 16) |
|||
{ |
|||
asm volatile ("movdqu %[inbuf_0], %%xmm5\n\t" |
|||
"movdqa %%xmm0, %%xmm6\n\t" |
|||
"pclmulqdq $0x00, %%xmm4, %%xmm0\n\t" |
|||
"pclmulqdq $0x11, %%xmm4, %%xmm6\n\t" |
|||
"pxor %%xmm5, %%xmm0\n\t" |
|||
"pxor %%xmm6, %%xmm0\n\t" |
|||
|
|||
"movdqu %[inbuf_1], %%xmm5\n\t" |
|||
"movdqa %%xmm1, %%xmm6\n\t" |
|||
"pclmulqdq $0x00, %%xmm4, %%xmm1\n\t" |
|||
"pclmulqdq $0x11, %%xmm4, %%xmm6\n\t" |
|||
"pxor %%xmm5, %%xmm1\n\t" |
|||
"pxor %%xmm6, %%xmm1\n\t" |
|||
|
|||
"movdqu %[inbuf_2], %%xmm5\n\t" |
|||
"movdqa %%xmm2, %%xmm6\n\t" |
|||
"pclmulqdq $0x00, %%xmm4, %%xmm2\n\t" |
|||
"pclmulqdq $0x11, %%xmm4, %%xmm6\n\t" |
|||
"pxor %%xmm5, %%xmm2\n\t" |
|||
"pxor %%xmm6, %%xmm2\n\t" |
|||
|
|||
"movdqu %[inbuf_3], %%xmm5\n\t" |
|||
"movdqa %%xmm3, %%xmm6\n\t" |
|||
"pclmulqdq $0x00, %%xmm4, %%xmm3\n\t" |
|||
"pclmulqdq $0x11, %%xmm4, %%xmm6\n\t" |
|||
"pxor %%xmm5, %%xmm3\n\t" |
|||
"pxor %%xmm6, %%xmm3\n\t" |
|||
: |
|||
: [inbuf_0] "m" (inbuf[0 * 16]), |
|||
[inbuf_1] "m" (inbuf[1 * 16]), |
|||
[inbuf_2] "m" (inbuf[2 * 16]), |
|||
[inbuf_3] "m" (inbuf[3 * 16]) |
|||
); |
|||
|
|||
inbuf += 4 * 16; |
|||
inlen -= 4 * 16; |
|||
} |
|||
|
|||
asm volatile ("movdqa %[k3k4], %%xmm6\n\t" |
|||
"movdqa %[my_p], %%xmm5\n\t" |
|||
: |
|||
: [k3k4] "m" (consts->k[3 - 1]), |
|||
[my_p] "m" (consts->my_p[0]) |
|||
); |
|||
|
|||
/* Fold 4 to 1. */ |
|||
|
|||
asm volatile ("movdqa %%xmm0, %%xmm4\n\t" |
|||
"pclmulqdq $0x00, %%xmm6, %%xmm0\n\t" |
|||
"pclmulqdq $0x11, %%xmm6, %%xmm4\n\t" |
|||
"pxor %%xmm1, %%xmm0\n\t" |
|||
"pxor %%xmm4, %%xmm0\n\t" |
|||
|
|||
"movdqa %%xmm0, %%xmm4\n\t" |
|||
"pclmulqdq $0x00, %%xmm6, %%xmm0\n\t" |
|||
"pclmulqdq $0x11, %%xmm6, %%xmm4\n\t" |
|||
"pxor %%xmm2, %%xmm0\n\t" |
|||
"pxor %%xmm4, %%xmm0\n\t" |
|||
|
|||
"movdqa %%xmm0, %%xmm4\n\t" |
|||
"pclmulqdq $0x00, %%xmm6, %%xmm0\n\t" |
|||
"pclmulqdq $0x11, %%xmm6, %%xmm4\n\t" |
|||
"pxor %%xmm3, %%xmm0\n\t" |
|||
"pxor %%xmm4, %%xmm0\n\t" |
|||
: |
|||
: |
|||
); |
|||
} |
|||
else |
|||
{ |
|||
asm volatile ("movd %[crc], %%xmm1\n\t" |
|||
"movdqu %[inbuf], %%xmm0\n\t" |
|||
"movdqa %[k3k4], %%xmm6\n\t" |
|||
"pxor %%xmm1, %%xmm0\n\t" |
|||
"movdqa %[my_p], %%xmm5\n\t" |
|||
: |
|||
: [inbuf] "m" (*inbuf), |
|||
[crc] "m" (*pcrc), |
|||
[k3k4] "m" (consts->k[3 - 1]), |
|||
[my_p] "m" (consts->my_p[0]) |
|||
); |
|||
|
|||
inbuf += 16; |
|||
inlen -= 16; |
|||
} |
|||
|
|||
/* Fold by 1. */ |
|||
if (inlen >= 16) |
|||
{ |
|||
while (inlen >= 16) |
|||
{ |
|||
/* Load next block to XMM2. Fold XMM0 to XMM0:XMM1. */ |
|||
asm volatile ("movdqu %[inbuf], %%xmm2\n\t" |
|||
"movdqa %%xmm0, %%xmm1\n\t" |
|||
"pclmulqdq $0x00, %%xmm6, %%xmm0\n\t" |
|||
"pclmulqdq $0x11, %%xmm6, %%xmm1\n\t" |
|||
"pxor %%xmm2, %%xmm0\n\t" |
|||
"pxor %%xmm1, %%xmm0\n\t" |
|||
: |
|||
: [inbuf] "m" (*inbuf) |
|||
); |
|||
|
|||
inbuf += 16; |
|||
inlen -= 16; |
|||
} |
|||
} |
|||
|
|||
/* Partial fold. */ |
|||
if (inlen) |
|||
{ |
|||
/* Load last input and add padding zeros. */ |
|||
asm volatile ("movdqu %[shr_shuf], %%xmm3\n\t" |
|||
"movdqu %[shl_shuf], %%xmm4\n\t" |
|||
"movdqu %[mask], %%xmm2\n\t" |
|||
|
|||
"movdqa %%xmm0, %%xmm1\n\t" |
|||
"pshufb %%xmm4, %%xmm0\n\t" |
|||
"movdqu %[inbuf], %%xmm4\n\t" |
|||
"pshufb %%xmm3, %%xmm1\n\t" |
|||
"pand %%xmm4, %%xmm2\n\t" |
|||
"por %%xmm1, %%xmm2\n\t" |
|||
|
|||
"movdqa %%xmm0, %%xmm1\n\t" |
|||
"pclmulqdq $0x00, %%xmm6, %%xmm0\n\t" |
|||
"pclmulqdq $0x11, %%xmm6, %%xmm1\n\t" |
|||
"pxor %%xmm2, %%xmm0\n\t" |
|||
"pxor %%xmm1, %%xmm0\n\t" |
|||
: |
|||
: [inbuf] "m" (*(inbuf - 16 + inlen)), |
|||
[mask] "m" (crc32_partial_fold_input_mask[inlen]), |
|||
[shl_shuf] "m" (crc32_refl_shuf_shift[inlen]), |
|||
[shr_shuf] "m" (crc32_refl_shuf_shift[inlen + 16]) |
|||
); |
|||
|
|||
inbuf += inlen; |
|||
inlen -= inlen; |
|||
} |
|||
|
|||
/* Final fold. */ |
|||
asm volatile (/* reduce 128-bits to 96-bits */ |
|||
"movdqa %%xmm0, %%xmm1\n\t" |
|||
"pclmulqdq $0x10, %%xmm6, %%xmm0\n\t" |
|||
"psrldq $8, %%xmm1\n\t" |
|||
"pxor %%xmm1, %%xmm0\n\t" |
|||
|
|||
/* reduce 96-bits to 64-bits */ |
|||
"pshufd $0xfc, %%xmm0, %%xmm1\n\t" /* [00][00][00][x] */ |
|||
"pshufd $0xf9, %%xmm0, %%xmm0\n\t" /* [00][00][x>>64][x>>32] */ |
|||
"pclmulqdq $0x00, %[k5], %%xmm1\n\t" /* [00][00][xx][xx] */ |
|||
"pxor %%xmm1, %%xmm0\n\t" /* top 64-bit are zero */ |
|||
|
|||
/* barrett reduction */ |
|||
"pshufd $0xf3, %%xmm0, %%xmm1\n\t" /* [00][00][x>>32][00] */ |
|||
"pslldq $4, %%xmm0\n\t" /* [??][x>>32][??][??] */ |
|||
"pclmulqdq $0x00, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */ |
|||
"pclmulqdq $0x10, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */ |
|||
"pxor %%xmm1, %%xmm0\n\t" |
|||
|
|||
/* store CRC */ |
|||
"pextrd $2, %%xmm0, %[out]\n\t" |
|||
: [out] "=m" (*pcrc) |
|||
: [k5] "m" (consts->k[5 - 1]) |
|||
); |
|||
} |
|||
|
|||
static inline void |
|||
crc32_reflected_less_than_16 (u32 *pcrc, const byte *inbuf, size_t inlen, |
|||
const struct crc32_consts_s *consts) |
|||
{ |
|||
if (inlen < 4) |
|||
{ |
|||
u32 crc = *pcrc; |
|||
u32 data; |
|||
|
|||
asm volatile ("movdqa %[my_p], %%xmm5\n\t" |
|||
: |
|||
: [my_p] "m" (consts->my_p[0]) |
|||
); |
|||
|
|||
if (inlen == 1) |
|||
{ |
|||
data = inbuf[0]; |
|||
data ^= crc; |
|||
data <<= 24; |
|||
crc >>= 8; |
|||
} |
|||
else if (inlen == 2) |
|||
{ |
|||
data = ((const struct u16_unaligned_s *)inbuf)->a; |
|||
data ^= crc; |
|||
data <<= 16; |
|||
crc >>= 16; |
|||
} |
|||
else |
|||
{ |
|||
data = ((const struct u16_unaligned_s *)inbuf)->a; |
|||
data |= inbuf[2] << 16; |
|||
data ^= crc; |
|||
data <<= 8; |
|||
crc >>= 24; |
|||
} |
|||
|
|||
/* Barrett reduction */ |
|||
asm volatile ("movd %[in], %%xmm0\n\t" |
|||
"movd %[crc], %%xmm1\n\t" |
|||
|
|||
"pclmulqdq $0x00, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */ |
|||
"psllq $32, %%xmm1\n\t" |
|||
"pshufd $0xfc, %%xmm0, %%xmm0\n\t" /* [00][00][00][x] */ |
|||
"pclmulqdq $0x10, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */ |
|||
"pxor %%xmm1, %%xmm0\n\t" |
|||
|
|||
"pextrd $1, %%xmm0, %[out]\n\t" |
|||
: [out] "=m" (*pcrc) |
|||
: [in] "rm" (data), |
|||
[crc] "rm" (crc) |
|||
); |
|||
} |
|||
else if (inlen == 4) |
|||
{ |
|||
/* Barrett reduction */ |
|||
asm volatile ("movd %[crc], %%xmm1\n\t" |
|||
"movd %[in], %%xmm0\n\t" |
|||
"movdqa %[my_p], %%xmm5\n\t" |
|||
"pxor %%xmm1, %%xmm0\n\t" |
|||
|
|||
"pclmulqdq $0x00, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */ |
|||
"pshufd $0xfc, %%xmm0, %%xmm0\n\t" /* [00][00][00][x] */ |
|||
"pclmulqdq $0x10, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */ |
|||
|
|||
"pextrd $1, %%xmm0, %[out]\n\t" |
|||
: [out] "=m" (*pcrc) |
|||
: [in] "m" (*inbuf), |
|||
[crc] "m" (*pcrc), |
|||
[my_p] "m" (consts->my_p[0]) |
|||
); |
|||
} |
|||
else |
|||
{ |
|||
asm volatile ("movdqu %[shuf], %%xmm4\n\t" |
|||
"movd %[crc], %%xmm1\n\t" |
|||
"movdqa %[my_p], %%xmm5\n\t" |
|||
"movdqa %[k3k4], %%xmm6\n\t" |
|||
: |
|||
: [shuf] "m" (crc32_refl_shuf_shift[inlen]), |
|||
[crc] "m" (*pcrc), |
|||
[my_p] "m" (consts->my_p[0]), |
|||
[k3k4] "m" (consts->k[3 - 1]) |
|||
); |
|||
|
|||
if (inlen >= 8) |
|||
{ |
|||
asm volatile ("movq %[inbuf], %%xmm0\n\t" |
|||
: |
|||
: [inbuf] "m" (*inbuf) |
|||
); |
|||
if (inlen > 8) |
|||
{ |
|||
asm volatile (/*"pinsrq $1, %[inbuf_tail], %%xmm0\n\t"*/ |
|||
"movq %[inbuf_tail], %%xmm2\n\t" |
|||
"punpcklqdq %%xmm2, %%xmm0\n\t" |
|||
"pshufb %[merge_shuf], %%xmm0\n\t" |
|||
: |
|||
: [inbuf_tail] "m" (inbuf[inlen - 8]), |
|||
[merge_shuf] "m" |
|||
(*crc32_merge9to15_shuf[inlen - 9]) |
|||
); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
asm volatile ("movd %[inbuf], %%xmm0\n\t" |
|||
"pinsrd $1, %[inbuf_tail], %%xmm0\n\t" |
|||
"pshufb %[merge_shuf], %%xmm0\n\t" |
|||
: |
|||
: [inbuf] "m" (*inbuf), |
|||
[inbuf_tail] "m" (inbuf[inlen - 4]), |
|||
[merge_shuf] "m" |
|||
(*crc32_merge5to7_shuf[inlen - 5]) |
|||
); |
|||
} |
|||
|
|||
/* Final fold. */ |
|||
asm volatile ("pxor %%xmm1, %%xmm0\n\t" |
|||
"pshufb %%xmm4, %%xmm0\n\t" |
|||
|
|||
/* reduce 128-bits to 96-bits */ |
|||
"movdqa %%xmm0, %%xmm1\n\t" |
|||
"pclmulqdq $0x10, %%xmm6, %%xmm0\n\t" |
|||
"psrldq $8, %%xmm1\n\t" |
|||
"pxor %%xmm1, %%xmm0\n\t" /* top 32-bit are zero */ |
|||
|
|||
/* reduce 96-bits to 64-bits */ |
|||
"pshufd $0xfc, %%xmm0, %%xmm1\n\t" /* [00][00][00][x] */ |
|||
"pshufd $0xf9, %%xmm0, %%xmm0\n\t" /* [00][00][x>>64][x>>32] */ |
|||
"pclmulqdq $0x00, %[k5], %%xmm1\n\t" /* [00][00][xx][xx] */ |
|||
"pxor %%xmm1, %%xmm0\n\t" /* top 64-bit are zero */ |
|||
|
|||
/* barrett reduction */ |
|||
"pshufd $0xf3, %%xmm0, %%xmm1\n\t" /* [00][00][x>>32][00] */ |
|||
"pslldq $4, %%xmm0\n\t" /* [??][x>>32][??][??] */ |
|||
"pclmulqdq $0x00, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */ |
|||
"pclmulqdq $0x10, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */ |
|||
"pxor %%xmm1, %%xmm0\n\t" |
|||
|
|||
/* store CRC */ |
|||
"pextrd $2, %%xmm0, %[out]\n\t" |
|||
: [out] "=m" (*pcrc) |
|||
: [k5] "m" (consts->k[5 - 1]) |
|||
); |
|||
} |
|||
} |
|||
|
|||
void |
|||
crc32_intel_pclmul (u32 *pcrc, const byte *inbuf, size_t inlen) |
|||
{ |
|||
const struct crc32_consts_s *consts = &crc32_consts; |
|||
#if defined(__x86_64__) && defined(__WIN64__) |
|||
char win64tmp[2 * 16]; |
|||
|
|||
/* XMM6-XMM7 need to be restored after use. */ |
|||
asm volatile ("movdqu %%xmm6, 0*16(%0)\n\t" |
|||
"movdqu %%xmm7, 1*16(%0)\n\t" |
|||
: |
|||
: "r" (win64tmp) |
|||
: "memory"); |
|||
#endif |
|||
|
|||
if (!inlen) |
|||
return; |
|||
|
|||
if (inlen >= 16) |
|||
crc32_reflected_bulk(pcrc, inbuf, inlen, consts); |
|||
else |
|||
crc32_reflected_less_than_16(pcrc, inbuf, inlen, consts); |
|||
|
|||
#if defined(__x86_64__) && defined(__WIN64__) |
|||
/* Restore used registers. */ |
|||
asm volatile("movdqu 0*16(%0), %%xmm6\n\t" |
|||
"movdqu 1*16(%0), %%xmm7\n\t" |
|||
: |
|||
: "r" (win64tmp) |
|||
: "memory"); |
|||
#endif |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,25 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2017 Percona LLC and/or its affiliates. |
|||
|
|||
CRC32 using Intel's PCLMUL instruction. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include <stdint.h> |
|||
#include <stddef.h> |
|||
|
|||
void |
|||
crc32_intel_pclmul(uint32_t *pcrc, const uint8_t *inbuf, size_t inlen); |
@ -0,0 +1,72 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2017 Percona LLC and/or its affiliates. |
|||
|
|||
Zlib compatible CRC-32 implementation. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include "crc_glue.h" |
|||
#include "crc-intel-pclmul.h" |
|||
#include <stdint.h> |
|||
#include <string.h> |
|||
#include <zlib.h> |
|||
|
|||
#if __GNUC__ >= 4 && defined(__x86_64__) |
|||
static int pclmul_enabled = 0; |
|||
#endif |
|||
|
|||
#if defined(__GNUC__) && defined(__x86_64__) |
|||
static |
|||
uint32_t |
|||
cpuid(uint32_t* ecx, uint32_t* edx) |
|||
{ |
|||
uint32_t level; |
|||
|
|||
asm("cpuid" : "=a" (level) : "a" (0) : "ebx", "ecx", "edx"); |
|||
|
|||
if (level < 1) { |
|||
return level; |
|||
} |
|||
|
|||
asm("cpuid" : "=c" (*ecx), "=d" (*edx) |
|||
: "a" (1) |
|||
: "ebx"); |
|||
|
|||
return level; |
|||
} |
|||
#endif |
|||
|
|||
void crc_init() { |
|||
#if defined(__GNUC__) && defined(__x86_64__) |
|||
uint32_t ecx, edx; |
|||
|
|||
if (cpuid(&ecx, &edx) > 0) { |
|||
pclmul_enabled = ((ecx >> 19) & 1) && ((ecx >> 1) & 1); |
|||
} |
|||
#endif |
|||
} |
|||
|
|||
unsigned long crc32_iso3309(unsigned long crc, const unsigned char *buf, unsigned int len) |
|||
{ |
|||
#if __GNUC__ >= 4 && defined(__x86_64__) && defined(HAVE_CLMUL_INSTRUCTION) |
|||
if (pclmul_enabled) { |
|||
uint32_t crc_accum = crc ^ 0xffffffffL; |
|||
crc32_intel_pclmul(&crc_accum, buf, len); |
|||
return crc_accum ^ 0xffffffffL; |
|||
} |
|||
#endif |
|||
return crc32(crc, buf, len); |
|||
} |
@ -0,0 +1,31 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2017 Percona LLC and/or its affiliates. |
|||
|
|||
Zlib compatible CRC-32 implementation. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
|
|||
#ifdef __cplusplus |
|||
extern "C" { |
|||
#endif |
|||
|
|||
void crc_init(); |
|||
unsigned long crc32_iso3309(unsigned long crc, const unsigned char *buf, unsigned int len); |
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
@ -0,0 +1,137 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2011-2013 Percona LLC and/or its affiliates. |
|||
|
|||
Data sink interface. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include <my_base.h> |
|||
#include "common.h" |
|||
#include "datasink.h" |
|||
#include "ds_compress.h" |
|||
#include "ds_archive.h" |
|||
#include "ds_xbstream.h" |
|||
#include "ds_local.h" |
|||
#include "ds_stdout.h" |
|||
#include "ds_tmpfile.h" |
|||
#include "ds_buffer.h" |
|||
|
|||
/************************************************************************ |
|||
Create a datasink of the specified type */ |
|||
ds_ctxt_t * |
|||
ds_create(const char *root, ds_type_t type) |
|||
{ |
|||
datasink_t *ds; |
|||
ds_ctxt_t *ctxt; |
|||
|
|||
switch (type) { |
|||
case DS_TYPE_STDOUT: |
|||
ds = &datasink_stdout; |
|||
break; |
|||
case DS_TYPE_LOCAL: |
|||
ds = &datasink_local; |
|||
break; |
|||
case DS_TYPE_ARCHIVE: |
|||
#ifdef HAVE_LIBARCHIVE |
|||
ds = &datasink_archive; |
|||
#else |
|||
msg("Error : mariabackup was built without libarchive support"); |
|||
exit(EXIT_FAILURE); |
|||
#endif |
|||
break; |
|||
case DS_TYPE_XBSTREAM: |
|||
ds = &datasink_xbstream; |
|||
break; |
|||
case DS_TYPE_COMPRESS: |
|||
ds = &datasink_compress; |
|||
break; |
|||
case DS_TYPE_ENCRYPT: |
|||
case DS_TYPE_DECRYPT: |
|||
msg("Error : mariabackup does not support encrypted backups."); |
|||
exit(EXIT_FAILURE); |
|||
break; |
|||
|
|||
case DS_TYPE_TMPFILE: |
|||
ds = &datasink_tmpfile; |
|||
break; |
|||
case DS_TYPE_BUFFER: |
|||
ds = &datasink_buffer; |
|||
break; |
|||
default: |
|||
msg("Unknown datasink type: %d\n", type); |
|||
xb_ad(0); |
|||
return NULL; |
|||
} |
|||
|
|||
ctxt = ds->init(root); |
|||
if (ctxt != NULL) { |
|||
ctxt->datasink = ds; |
|||
} else { |
|||
msg("Error: failed to initialize datasink.\n"); |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
return ctxt; |
|||
} |
|||
|
|||
/************************************************************************ |
|||
Open a datasink file */ |
|||
ds_file_t * |
|||
ds_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *stat) |
|||
{ |
|||
ds_file_t *file; |
|||
|
|||
file = ctxt->datasink->open(ctxt, path, stat); |
|||
if (file != NULL) { |
|||
file->datasink = ctxt->datasink; |
|||
} |
|||
|
|||
return file; |
|||
} |
|||
|
|||
/************************************************************************ |
|||
Write to a datasink file. |
|||
@return 0 on success, 1 on error. */ |
|||
int |
|||
ds_write(ds_file_t *file, const void *buf, size_t len) |
|||
{ |
|||
return file->datasink->write(file, buf, len); |
|||
} |
|||
|
|||
/************************************************************************ |
|||
Close a datasink file. |
|||
@return 0 on success, 1, on error. */ |
|||
int |
|||
ds_close(ds_file_t *file) |
|||
{ |
|||
return file->datasink->close(file); |
|||
} |
|||
|
|||
/************************************************************************ |
|||
Destroy a datasink handle */ |
|||
void |
|||
ds_destroy(ds_ctxt_t *ctxt) |
|||
{ |
|||
ctxt->datasink->deinit(ctxt); |
|||
} |
|||
|
|||
/************************************************************************ |
|||
Set the destination pipe for a datasink (only makes sense for compress and |
|||
tmpfile). */ |
|||
void ds_set_pipe(ds_ctxt_t *ctxt, ds_ctxt_t *pipe_ctxt) |
|||
{ |
|||
ctxt->pipe_ctxt = pipe_ctxt; |
|||
} |
@ -0,0 +1,100 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2011-2013 Percona LLC and/or its affiliates. |
|||
|
|||
Data sink interface. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef XB_DATASINK_H |
|||
#define XB_DATASINK_H |
|||
|
|||
#include <my_global.h> |
|||
#include <my_dir.h> |
|||
|
|||
#ifdef __cplusplus |
|||
extern "C" { |
|||
#endif |
|||
|
|||
extern char *xtrabackup_tmpdir; |
|||
struct datasink_struct; |
|||
typedef struct datasink_struct datasink_t; |
|||
|
|||
typedef struct ds_ctxt { |
|||
datasink_t *datasink; |
|||
char *root; |
|||
void *ptr; |
|||
struct ds_ctxt *pipe_ctxt; |
|||
} ds_ctxt_t; |
|||
|
|||
typedef struct { |
|||
void *ptr; |
|||
char *path; |
|||
datasink_t *datasink; |
|||
} ds_file_t; |
|||
|
|||
struct datasink_struct { |
|||
ds_ctxt_t *(*init)(const char *root); |
|||
ds_file_t *(*open)(ds_ctxt_t *ctxt, const char *path, MY_STAT *stat); |
|||
int (*write)(ds_file_t *file, const void *buf, size_t len); |
|||
int (*close)(ds_file_t *file); |
|||
void (*deinit)(ds_ctxt_t *ctxt); |
|||
}; |
|||
|
|||
/* Supported datasink types */ |
|||
typedef enum { |
|||
DS_TYPE_STDOUT, |
|||
DS_TYPE_LOCAL, |
|||
DS_TYPE_ARCHIVE, |
|||
DS_TYPE_XBSTREAM, |
|||
DS_TYPE_COMPRESS, |
|||
DS_TYPE_ENCRYPT, |
|||
DS_TYPE_DECRYPT, |
|||
DS_TYPE_TMPFILE, |
|||
DS_TYPE_BUFFER |
|||
} ds_type_t; |
|||
|
|||
/************************************************************************ |
|||
Create a datasink of the specified type */ |
|||
ds_ctxt_t *ds_create(const char *root, ds_type_t type); |
|||
|
|||
/************************************************************************ |
|||
Open a datasink file */ |
|||
ds_file_t *ds_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *stat); |
|||
|
|||
/************************************************************************ |
|||
Write to a datasink file. |
|||
@return 0 on success, 1 on error. */ |
|||
int ds_write(ds_file_t *file, const void *buf, size_t len); |
|||
|
|||
/************************************************************************ |
|||
Close a datasink file. |
|||
@return 0 on success, 1, on error. */ |
|||
int ds_close(ds_file_t *file); |
|||
|
|||
/************************************************************************ |
|||
Destroy a datasink handle */ |
|||
void ds_destroy(ds_ctxt_t *ctxt); |
|||
|
|||
/************************************************************************ |
|||
Set the destination pipe for a datasink (only makes sense for compress and |
|||
tmpfile). */ |
|||
void ds_set_pipe(ds_ctxt_t *ctxt, ds_ctxt_t *pipe_ctxt); |
|||
|
|||
#ifdef __cplusplus |
|||
} /* extern "C" */ |
|||
#endif |
|||
|
|||
#endif /* XB_DATASINK_H */ |
@ -0,0 +1,280 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2013 Percona LLC and/or its affiliates. |
|||
|
|||
Streaming implementation for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include <my_base.h> |
|||
#include <archive.h> |
|||
#include <archive_entry.h> |
|||
#include "common.h" |
|||
#include "datasink.h" |
|||
|
|||
#if ARCHIVE_VERSION_NUMBER < 3000000 |
|||
#define archive_write_add_filter_none(X) archive_write_set_compression_none(X) |
|||
#define archive_write_free(X) archive_write_finish(X) |
|||
#endif |
|||
|
|||
typedef struct { |
|||
struct archive *archive; |
|||
ds_file_t *dest_file; |
|||
pthread_mutex_t mutex; |
|||
} ds_archive_ctxt_t; |
|||
|
|||
typedef struct { |
|||
struct archive_entry *entry; |
|||
ds_archive_ctxt_t *archive_ctxt; |
|||
} ds_archive_file_t; |
|||
|
|||
|
|||
/*********************************************************************** |
|||
General archive interface */ |
|||
|
|||
static ds_ctxt_t *archive_init(const char *root); |
|||
static ds_file_t *archive_open(ds_ctxt_t *ctxt, const char *path, |
|||
MY_STAT *mystat); |
|||
static int archive_write(ds_file_t *file, const void *buf, size_t len); |
|||
static int archive_close(ds_file_t *file); |
|||
static void archive_deinit(ds_ctxt_t *ctxt); |
|||
|
|||
datasink_t datasink_archive = { |
|||
&archive_init, |
|||
&archive_open, |
|||
&archive_write, |
|||
&archive_close, |
|||
&archive_deinit |
|||
}; |
|||
|
|||
static |
|||
int |
|||
my_archive_open_callback(struct archive *a __attribute__((unused)), |
|||
void *data __attribute__((unused))) |
|||
{ |
|||
return ARCHIVE_OK; |
|||
} |
|||
|
|||
static |
|||
ssize_t |
|||
my_archive_write_callback(struct archive *a __attribute__((unused)), |
|||
void *data, const void *buffer, size_t length) |
|||
{ |
|||
ds_archive_ctxt_t *archive_ctxt; |
|||
|
|||
archive_ctxt = (ds_archive_ctxt_t *) data; |
|||
|
|||
xb_ad(archive_ctxt != NULL); |
|||
xb_ad(archive_ctxt->dest_file != NULL); |
|||
|
|||
if (!ds_write(archive_ctxt->dest_file, buffer, length)) { |
|||
return length; |
|||
} |
|||
return -1; |
|||
} |
|||
|
|||
static |
|||
int |
|||
my_archive_close_callback(struct archive *a __attribute__((unused)), |
|||
void *data __attribute__((unused))) |
|||
{ |
|||
return ARCHIVE_OK; |
|||
} |
|||
|
|||
static |
|||
ds_ctxt_t * |
|||
archive_init(const char *root __attribute__((unused))) |
|||
{ |
|||
ds_ctxt_t *ctxt; |
|||
ds_archive_ctxt_t *archive_ctxt; |
|||
struct archive *a; |
|||
|
|||
ctxt = my_malloc(sizeof(ds_ctxt_t) + sizeof(ds_archive_ctxt_t), |
|||
MYF(MY_FAE)); |
|||
archive_ctxt = (ds_archive_ctxt_t *)(ctxt + 1); |
|||
|
|||
if (pthread_mutex_init(&archive_ctxt->mutex, NULL)) { |
|||
msg("archive_init: pthread_mutex_init() failed.\n"); |
|||
goto err; |
|||
} |
|||
|
|||
a = archive_write_new(); |
|||
if (a == NULL) { |
|||
msg("archive_write_new() failed.\n"); |
|||
goto err; |
|||
} |
|||
|
|||
archive_ctxt->archive = a; |
|||
archive_ctxt->dest_file = NULL; |
|||
|
|||
if(archive_write_add_filter_none(a) != ARCHIVE_OK || |
|||
archive_write_set_format_pax_restricted(a) != ARCHIVE_OK || |
|||
/* disable internal buffering so we don't have to flush the |
|||
output in xtrabackup */ |
|||
archive_write_set_bytes_per_block(a, 0) != ARCHIVE_OK) { |
|||
msg("failed to set libarchive archive options: %s\n", |
|||
archive_error_string(a)); |
|||
archive_write_free(a); |
|||
goto err; |
|||
} |
|||
|
|||
if (archive_write_open(a, archive_ctxt, my_archive_open_callback, |
|||
my_archive_write_callback, |
|||
my_archive_close_callback) != ARCHIVE_OK) { |
|||
msg("cannot open output archive.\n"); |
|||
return NULL; |
|||
} |
|||
|
|||
ctxt->ptr = archive_ctxt; |
|||
|
|||
return ctxt; |
|||
|
|||
err: |
|||
my_free(ctxt); |
|||
return NULL; |
|||
} |
|||
|
|||
static |
|||
ds_file_t * |
|||
archive_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) |
|||
{ |
|||
ds_archive_ctxt_t *archive_ctxt; |
|||
ds_ctxt_t *dest_ctxt; |
|||
ds_file_t *file; |
|||
ds_archive_file_t *archive_file; |
|||
|
|||
struct archive *a; |
|||
struct archive_entry *entry; |
|||
|
|||
xb_ad(ctxt->pipe_ctxt != NULL); |
|||
dest_ctxt = ctxt->pipe_ctxt; |
|||
|
|||
archive_ctxt = (ds_archive_ctxt_t *) ctxt->ptr; |
|||
|
|||
pthread_mutex_lock(&archive_ctxt->mutex); |
|||
if (archive_ctxt->dest_file == NULL) { |
|||
archive_ctxt->dest_file = ds_open(dest_ctxt, path, mystat); |
|||
if (archive_ctxt->dest_file == NULL) { |
|||
return NULL; |
|||
} |
|||
} |
|||
pthread_mutex_unlock(&archive_ctxt->mutex); |
|||
|
|||
file = (ds_file_t *) my_malloc(sizeof(ds_file_t) + |
|||
sizeof(ds_archive_file_t), |
|||
MYF(MY_FAE)); |
|||
|
|||
archive_file = (ds_archive_file_t *) (file + 1); |
|||
|
|||
a = archive_ctxt->archive; |
|||
|
|||
entry = archive_entry_new(); |
|||
if (entry == NULL) { |
|||
msg("archive_entry_new() failed.\n"); |
|||
goto err; |
|||
} |
|||
|
|||
archive_entry_set_size(entry, mystat->st_size); |
|||
archive_entry_set_mode(entry, 0660); |
|||
archive_entry_set_filetype(entry, AE_IFREG); |
|||
archive_entry_set_pathname(entry, path); |
|||
archive_entry_set_mtime(entry, mystat->st_mtime, 0); |
|||
|
|||
archive_file->entry = entry; |
|||
archive_file->archive_ctxt = archive_ctxt; |
|||
|
|||
if (archive_write_header(a, entry) != ARCHIVE_OK) { |
|||
msg("archive_write_header() failed.\n"); |
|||
archive_entry_free(entry); |
|||
goto err; |
|||
} |
|||
|
|||
file->ptr = archive_file; |
|||
file->path = archive_ctxt->dest_file->path; |
|||
|
|||
return file; |
|||
|
|||
err: |
|||
if (archive_ctxt->dest_file) { |
|||
ds_close(archive_ctxt->dest_file); |
|||
archive_ctxt->dest_file = NULL; |
|||
} |
|||
my_free(file); |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
static |
|||
int |
|||
archive_write(ds_file_t *file, const void *buf, size_t len) |
|||
{ |
|||
ds_archive_file_t *archive_file; |
|||
struct archive *a; |
|||
|
|||
archive_file = (ds_archive_file_t *) file->ptr; |
|||
|
|||
a = archive_file->archive_ctxt->archive; |
|||
|
|||
xb_ad(archive_file->archive_ctxt->dest_file != NULL); |
|||
if (archive_write_data(a, buf, len) < 0) { |
|||
msg("archive_write_data() failed: %s (errno = %d)\n", |
|||
archive_error_string(a), archive_errno(a)); |
|||
return 1; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static |
|||
int |
|||
archive_close(ds_file_t *file) |
|||
{ |
|||
ds_archive_file_t *archive_file; |
|||
int rc = 0; |
|||
|
|||
archive_file = (ds_archive_file_t *)file->ptr; |
|||
|
|||
archive_entry_free(archive_file->entry); |
|||
|
|||
my_free(file); |
|||
|
|||
return rc; |
|||
} |
|||
|
|||
static |
|||
void |
|||
archive_deinit(ds_ctxt_t *ctxt) |
|||
{ |
|||
struct archive *a; |
|||
ds_archive_ctxt_t *archive_ctxt; |
|||
|
|||
archive_ctxt = (ds_archive_ctxt_t *) ctxt->ptr; |
|||
|
|||
a = archive_ctxt->archive; |
|||
|
|||
if (archive_write_close(a) != ARCHIVE_OK) { |
|||
msg("archive_write_close() failed.\n"); |
|||
} |
|||
archive_write_free(a); |
|||
|
|||
if (archive_ctxt->dest_file) { |
|||
ds_close(archive_ctxt->dest_file); |
|||
archive_ctxt->dest_file = NULL; |
|||
} |
|||
|
|||
pthread_mutex_destroy(&archive_ctxt->mutex); |
|||
|
|||
my_free(ctxt); |
|||
} |
@ -0,0 +1,28 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2013 Percona LLC and/or its affiliates. |
|||
|
|||
Streaming interface for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef DS_ARCHIVE_H |
|||
#define DS_ARCHIVE_H |
|||
|
|||
#include "datasink.h" |
|||
|
|||
extern datasink_t datasink_archive; |
|||
|
|||
#endif |
@ -0,0 +1,189 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2012-2013 Percona LLC and/or its affiliates. |
|||
|
|||
buffer datasink for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
/* Does buffered output to a destination datasink set with ds_set_pipe(). |
|||
Writes to the destination datasink are guaranteed to not be smaller than a |
|||
specified buffer size (DS_DEFAULT_BUFFER_SIZE by default), with the only |
|||
exception for the last write for a file. */ |
|||
|
|||
#include <mysql_version.h> |
|||
#include <my_base.h> |
|||
#include "ds_buffer.h" |
|||
#include "common.h" |
|||
#include "datasink.h" |
|||
|
|||
#define DS_DEFAULT_BUFFER_SIZE (64 * 1024) |
|||
|
|||
typedef struct { |
|||
ds_file_t *dst_file; |
|||
char *buf; |
|||
size_t pos; |
|||
size_t size; |
|||
} ds_buffer_file_t; |
|||
|
|||
typedef struct { |
|||
size_t buffer_size; |
|||
} ds_buffer_ctxt_t; |
|||
|
|||
static ds_ctxt_t *buffer_init(const char *root); |
|||
static ds_file_t *buffer_open(ds_ctxt_t *ctxt, const char *path, |
|||
MY_STAT *mystat); |
|||
static int buffer_write(ds_file_t *file, const void *buf, size_t len); |
|||
static int buffer_close(ds_file_t *file); |
|||
static void buffer_deinit(ds_ctxt_t *ctxt); |
|||
|
|||
datasink_t datasink_buffer = { |
|||
&buffer_init, |
|||
&buffer_open, |
|||
&buffer_write, |
|||
&buffer_close, |
|||
&buffer_deinit |
|||
}; |
|||
|
|||
/* Change the default buffer size */ |
|||
void ds_buffer_set_size(ds_ctxt_t *ctxt, size_t size) |
|||
{ |
|||
ds_buffer_ctxt_t *buffer_ctxt = (ds_buffer_ctxt_t *) ctxt->ptr; |
|||
|
|||
buffer_ctxt->buffer_size = size; |
|||
} |
|||
|
|||
static ds_ctxt_t * |
|||
buffer_init(const char *root) |
|||
{ |
|||
ds_ctxt_t *ctxt; |
|||
ds_buffer_ctxt_t *buffer_ctxt; |
|||
|
|||
ctxt = my_malloc(sizeof(ds_ctxt_t) + sizeof(ds_buffer_ctxt_t), |
|||
MYF(MY_FAE)); |
|||
buffer_ctxt = (ds_buffer_ctxt_t *) (ctxt + 1); |
|||
buffer_ctxt->buffer_size = DS_DEFAULT_BUFFER_SIZE; |
|||
|
|||
ctxt->ptr = buffer_ctxt; |
|||
ctxt->root = my_strdup(root, MYF(MY_FAE)); |
|||
|
|||
return ctxt; |
|||
} |
|||
|
|||
static ds_file_t * |
|||
buffer_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) |
|||
{ |
|||
ds_buffer_ctxt_t *buffer_ctxt; |
|||
ds_ctxt_t *pipe_ctxt; |
|||
ds_file_t *dst_file; |
|||
ds_file_t *file; |
|||
ds_buffer_file_t *buffer_file; |
|||
|
|||
pipe_ctxt = ctxt->pipe_ctxt; |
|||
xb_a(pipe_ctxt != NULL); |
|||
|
|||
dst_file = ds_open(pipe_ctxt, path, mystat); |
|||
if (dst_file == NULL) { |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
buffer_ctxt = (ds_buffer_ctxt_t *) ctxt->ptr; |
|||
|
|||
file = (ds_file_t *) my_malloc(sizeof(ds_file_t) + |
|||
sizeof(ds_buffer_file_t) + |
|||
buffer_ctxt->buffer_size, |
|||
MYF(MY_FAE)); |
|||
|
|||
buffer_file = (ds_buffer_file_t *) (file + 1); |
|||
buffer_file->dst_file = dst_file; |
|||
buffer_file->buf = (char *) (buffer_file + 1); |
|||
buffer_file->size = buffer_ctxt->buffer_size; |
|||
buffer_file->pos = 0; |
|||
|
|||
file->path = dst_file->path; |
|||
file->ptr = buffer_file; |
|||
|
|||
return file; |
|||
} |
|||
|
|||
static int |
|||
buffer_write(ds_file_t *file, const void *buf, size_t len) |
|||
{ |
|||
ds_buffer_file_t *buffer_file; |
|||
|
|||
buffer_file = (ds_buffer_file_t *) file->ptr; |
|||
|
|||
while (len > 0) { |
|||
if (buffer_file->pos + len > buffer_file->size) { |
|||
if (buffer_file->pos > 0) { |
|||
size_t bytes; |
|||
|
|||
bytes = buffer_file->size - buffer_file->pos; |
|||
memcpy(buffer_file->buf + buffer_file->pos, buf, |
|||
bytes); |
|||
|
|||
if (ds_write(buffer_file->dst_file, |
|||
buffer_file->buf, |
|||
buffer_file->size)) { |
|||
return 1; |
|||
} |
|||
|
|||
buffer_file->pos = 0; |
|||
|
|||
buf = (const char *) buf + bytes; |
|||
len -= bytes; |
|||
} else { |
|||
/* We don't have any buffered bytes, just write |
|||
the entire source buffer */ |
|||
if (ds_write(buffer_file->dst_file, buf, len)) { |
|||
return 1; |
|||
} |
|||
break; |
|||
} |
|||
} else { |
|||
memcpy(buffer_file->buf + buffer_file->pos, buf, len); |
|||
buffer_file->pos += len; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static int |
|||
buffer_close(ds_file_t *file) |
|||
{ |
|||
ds_buffer_file_t *buffer_file; |
|||
int ret; |
|||
|
|||
buffer_file = (ds_buffer_file_t *) file->ptr; |
|||
if (buffer_file->pos > 0) { |
|||
ds_write(buffer_file->dst_file, buffer_file->buf, |
|||
buffer_file->pos); |
|||
} |
|||
|
|||
ret = ds_close(buffer_file->dst_file); |
|||
|
|||
my_free(file); |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
static void |
|||
buffer_deinit(ds_ctxt_t *ctxt) |
|||
{ |
|||
my_free(ctxt->root); |
|||
my_free(ctxt); |
|||
} |
@ -0,0 +1,39 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2012-2013 Percona LLC and/or its affiliates. |
|||
|
|||
buffer datasink for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef DS_BUFFER_H |
|||
#define DS_BUFFER_H |
|||
|
|||
#include "datasink.h" |
|||
|
|||
#ifdef __cplusplus |
|||
extern "C" { |
|||
#endif |
|||
|
|||
extern datasink_t datasink_buffer; |
|||
|
|||
/* Change the default buffer size */ |
|||
void ds_buffer_set_size(ds_ctxt_t *ctxt, size_t size); |
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
|
|||
#endif |
@ -0,0 +1,462 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2011-2013 Percona LLC and/or its affiliates. |
|||
|
|||
Compressing datasink implementation for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include <mysql_version.h> |
|||
#include <my_base.h> |
|||
#include <quicklz.h> |
|||
#include <zlib.h> |
|||
#include "common.h" |
|||
#include "datasink.h" |
|||
|
|||
#define COMPRESS_CHUNK_SIZE ((size_t) (xtrabackup_compress_chunk_size)) |
|||
#define MY_QLZ_COMPRESS_OVERHEAD 400 |
|||
|
|||
typedef struct { |
|||
pthread_t id; |
|||
uint num; |
|||
pthread_mutex_t ctrl_mutex; |
|||
pthread_cond_t ctrl_cond; |
|||
pthread_mutex_t data_mutex; |
|||
pthread_cond_t data_cond; |
|||
my_bool started; |
|||
my_bool data_avail; |
|||
my_bool cancelled; |
|||
const char *from; |
|||
size_t from_len; |
|||
char *to; |
|||
size_t to_len; |
|||
qlz_state_compress state; |
|||
ulong adler; |
|||
} comp_thread_ctxt_t; |
|||
|
|||
typedef struct { |
|||
comp_thread_ctxt_t *threads; |
|||
uint nthreads; |
|||
} ds_compress_ctxt_t; |
|||
|
|||
typedef struct { |
|||
ds_file_t *dest_file; |
|||
ds_compress_ctxt_t *comp_ctxt; |
|||
size_t bytes_processed; |
|||
} ds_compress_file_t; |
|||
|
|||
/* Compression options */ |
|||
extern char *xtrabackup_compress_alg; |
|||
extern uint xtrabackup_compress_threads; |
|||
extern ulonglong xtrabackup_compress_chunk_size; |
|||
|
|||
static ds_ctxt_t *compress_init(const char *root); |
|||
static ds_file_t *compress_open(ds_ctxt_t *ctxt, const char *path, |
|||
MY_STAT *mystat); |
|||
static int compress_write(ds_file_t *file, const void *buf, size_t len); |
|||
static int compress_close(ds_file_t *file); |
|||
static void compress_deinit(ds_ctxt_t *ctxt); |
|||
|
|||
datasink_t datasink_compress = { |
|||
&compress_init, |
|||
&compress_open, |
|||
&compress_write, |
|||
&compress_close, |
|||
&compress_deinit |
|||
}; |
|||
|
|||
static inline int write_uint32_le(ds_file_t *file, ulong n); |
|||
static inline int write_uint64_le(ds_file_t *file, ulonglong n); |
|||
|
|||
static comp_thread_ctxt_t *create_worker_threads(uint n); |
|||
static void destroy_worker_threads(comp_thread_ctxt_t *threads, uint n); |
|||
static void *compress_worker_thread_func(void *arg); |
|||
|
|||
static |
|||
ds_ctxt_t * |
|||
compress_init(const char *root) |
|||
{ |
|||
ds_ctxt_t *ctxt; |
|||
ds_compress_ctxt_t *compress_ctxt; |
|||
comp_thread_ctxt_t *threads; |
|||
|
|||
/* Create and initialize the worker threads */ |
|||
threads = create_worker_threads(xtrabackup_compress_threads); |
|||
if (threads == NULL) { |
|||
msg("compress: failed to create worker threads.\n"); |
|||
return NULL; |
|||
} |
|||
|
|||
ctxt = (ds_ctxt_t *) my_malloc(sizeof(ds_ctxt_t) + |
|||
sizeof(ds_compress_ctxt_t), |
|||
MYF(MY_FAE)); |
|||
|
|||
compress_ctxt = (ds_compress_ctxt_t *) (ctxt + 1); |
|||
compress_ctxt->threads = threads; |
|||
compress_ctxt->nthreads = xtrabackup_compress_threads; |
|||
|
|||
ctxt->ptr = compress_ctxt; |
|||
ctxt->root = my_strdup(root, MYF(MY_FAE)); |
|||
|
|||
return ctxt; |
|||
} |
|||
|
|||
static |
|||
ds_file_t * |
|||
compress_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) |
|||
{ |
|||
ds_compress_ctxt_t *comp_ctxt; |
|||
ds_ctxt_t *dest_ctxt; |
|||
ds_file_t *dest_file; |
|||
char new_name[FN_REFLEN]; |
|||
size_t name_len; |
|||
ds_file_t *file; |
|||
ds_compress_file_t *comp_file; |
|||
|
|||
xb_ad(ctxt->pipe_ctxt != NULL); |
|||
dest_ctxt = ctxt->pipe_ctxt; |
|||
|
|||
comp_ctxt = (ds_compress_ctxt_t *) ctxt->ptr; |
|||
|
|||
/* Append the .qp extension to the filename */ |
|||
fn_format(new_name, path, "", ".qp", MYF(MY_APPEND_EXT)); |
|||
|
|||
dest_file = ds_open(dest_ctxt, new_name, mystat); |
|||
if (dest_file == NULL) { |
|||
return NULL; |
|||
} |
|||
|
|||
/* Write the qpress archive header */ |
|||
if (ds_write(dest_file, "qpress10", 8) || |
|||
write_uint64_le(dest_file, COMPRESS_CHUNK_SIZE)) { |
|||
goto err; |
|||
} |
|||
|
|||
/* We are going to create a one-file "flat" (i.e. with no |
|||
subdirectories) archive. So strip the directory part from the path and |
|||
remove the '.qp' suffix. */ |
|||
fn_format(new_name, path, "", "", MYF(MY_REPLACE_DIR)); |
|||
|
|||
/* Write the qpress file header */ |
|||
name_len = strlen(new_name); |
|||
if (ds_write(dest_file, "F", 1) || |
|||
write_uint32_le(dest_file, (uint)name_len) || |
|||
/* we want to write the terminating \0 as well */ |
|||
ds_write(dest_file, new_name, name_len + 1)) { |
|||
goto err; |
|||
} |
|||
|
|||
file = (ds_file_t *) my_malloc(sizeof(ds_file_t) + |
|||
sizeof(ds_compress_file_t), |
|||
MYF(MY_FAE)); |
|||
comp_file = (ds_compress_file_t *) (file + 1); |
|||
comp_file->dest_file = dest_file; |
|||
comp_file->comp_ctxt = comp_ctxt; |
|||
comp_file->bytes_processed = 0; |
|||
|
|||
file->ptr = comp_file; |
|||
file->path = dest_file->path; |
|||
|
|||
return file; |
|||
|
|||
err: |
|||
ds_close(dest_file); |
|||
return NULL; |
|||
} |
|||
|
|||
static |
|||
int |
|||
compress_write(ds_file_t *file, const void *buf, size_t len) |
|||
{ |
|||
ds_compress_file_t *comp_file; |
|||
ds_compress_ctxt_t *comp_ctxt; |
|||
comp_thread_ctxt_t *threads; |
|||
comp_thread_ctxt_t *thd; |
|||
uint nthreads; |
|||
uint i; |
|||
const char *ptr; |
|||
ds_file_t *dest_file; |
|||
|
|||
comp_file = (ds_compress_file_t *) file->ptr; |
|||
comp_ctxt = comp_file->comp_ctxt; |
|||
dest_file = comp_file->dest_file; |
|||
|
|||
threads = comp_ctxt->threads; |
|||
nthreads = comp_ctxt->nthreads; |
|||
|
|||
ptr = (const char *) buf; |
|||
while (len > 0) { |
|||
uint max_thread; |
|||
|
|||
/* Send data to worker threads for compression */ |
|||
for (i = 0; i < nthreads; i++) { |
|||
size_t chunk_len; |
|||
|
|||
thd = threads + i; |
|||
|
|||
pthread_mutex_lock(&thd->ctrl_mutex); |
|||
|
|||
chunk_len = (len > COMPRESS_CHUNK_SIZE) ? |
|||
COMPRESS_CHUNK_SIZE : len; |
|||
thd->from = ptr; |
|||
thd->from_len = chunk_len; |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
thd->data_avail = TRUE; |
|||
pthread_cond_signal(&thd->data_cond); |
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
|
|||
len -= chunk_len; |
|||
if (len == 0) { |
|||
break; |
|||
} |
|||
ptr += chunk_len; |
|||
} |
|||
|
|||
max_thread = (i < nthreads) ? i : nthreads - 1; |
|||
|
|||
/* Reap and stream the compressed data */ |
|||
for (i = 0; i <= max_thread; i++) { |
|||
thd = threads + i; |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
while (thd->data_avail == TRUE) { |
|||
pthread_cond_wait(&thd->data_cond, |
|||
&thd->data_mutex); |
|||
} |
|||
|
|||
xb_a(threads[i].to_len > 0); |
|||
|
|||
if (ds_write(dest_file, "NEWBNEWB", 8) || |
|||
write_uint64_le(dest_file, |
|||
comp_file->bytes_processed)) { |
|||
msg("compress: write to the destination stream " |
|||
"failed.\n"); |
|||
return 1; |
|||
} |
|||
|
|||
comp_file->bytes_processed += threads[i].from_len; |
|||
|
|||
if (write_uint32_le(dest_file, threads[i].adler) || |
|||
ds_write(dest_file, threads[i].to, |
|||
threads[i].to_len)) { |
|||
msg("compress: write to the destination stream " |
|||
"failed.\n"); |
|||
return 1; |
|||
} |
|||
|
|||
pthread_mutex_unlock(&threads[i].data_mutex); |
|||
pthread_mutex_unlock(&threads[i].ctrl_mutex); |
|||
} |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static |
|||
int |
|||
compress_close(ds_file_t *file) |
|||
{ |
|||
ds_compress_file_t *comp_file; |
|||
ds_file_t *dest_file; |
|||
int rc; |
|||
|
|||
comp_file = (ds_compress_file_t *) file->ptr; |
|||
dest_file = comp_file->dest_file; |
|||
|
|||
/* Write the qpress file trailer */ |
|||
ds_write(dest_file, "ENDSENDS", 8); |
|||
|
|||
/* Supposedly the number of written bytes should be written as a |
|||
"recovery information" in the file trailer, but in reality qpress |
|||
always writes 8 zeros here. Let's do the same */ |
|||
|
|||
write_uint64_le(dest_file, 0); |
|||
|
|||
rc = ds_close(dest_file); |
|||
|
|||
my_free(file); |
|||
|
|||
return rc; |
|||
} |
|||
|
|||
static |
|||
void |
|||
compress_deinit(ds_ctxt_t *ctxt) |
|||
{ |
|||
ds_compress_ctxt_t *comp_ctxt; |
|||
|
|||
xb_ad(ctxt->pipe_ctxt != NULL); |
|||
|
|||
comp_ctxt = (ds_compress_ctxt_t *) ctxt->ptr;; |
|||
|
|||
destroy_worker_threads(comp_ctxt->threads, comp_ctxt->nthreads); |
|||
|
|||
my_free(ctxt->root); |
|||
my_free(ctxt); |
|||
} |
|||
|
|||
static inline |
|||
int |
|||
write_uint32_le(ds_file_t *file, ulong n) |
|||
{ |
|||
char tmp[4]; |
|||
|
|||
int4store(tmp, n); |
|||
return ds_write(file, tmp, sizeof(tmp)); |
|||
} |
|||
|
|||
static inline |
|||
int |
|||
write_uint64_le(ds_file_t *file, ulonglong n) |
|||
{ |
|||
char tmp[8]; |
|||
|
|||
int8store(tmp, n); |
|||
return ds_write(file, tmp, sizeof(tmp)); |
|||
} |
|||
|
|||
static |
|||
comp_thread_ctxt_t * |
|||
create_worker_threads(uint n) |
|||
{ |
|||
comp_thread_ctxt_t *threads; |
|||
uint i; |
|||
|
|||
threads = (comp_thread_ctxt_t *) |
|||
my_malloc(sizeof(comp_thread_ctxt_t) * n, MYF(MY_FAE)); |
|||
|
|||
for (i = 0; i < n; i++) { |
|||
comp_thread_ctxt_t *thd = threads + i; |
|||
|
|||
thd->num = i + 1; |
|||
thd->started = FALSE; |
|||
thd->cancelled = FALSE; |
|||
thd->data_avail = FALSE; |
|||
|
|||
thd->to = (char *) my_malloc(COMPRESS_CHUNK_SIZE + |
|||
MY_QLZ_COMPRESS_OVERHEAD, |
|||
MYF(MY_FAE)); |
|||
|
|||
/* Initialize the control mutex and condition var */ |
|||
if (pthread_mutex_init(&thd->ctrl_mutex, NULL) || |
|||
pthread_cond_init(&thd->ctrl_cond, NULL)) { |
|||
goto err; |
|||
} |
|||
|
|||
/* Initialize and data mutex and condition var */ |
|||
if (pthread_mutex_init(&thd->data_mutex, NULL) || |
|||
pthread_cond_init(&thd->data_cond, NULL)) { |
|||
goto err; |
|||
} |
|||
|
|||
pthread_mutex_lock(&thd->ctrl_mutex); |
|||
|
|||
if (pthread_create(&thd->id, NULL, compress_worker_thread_func, |
|||
thd)) { |
|||
msg("compress: pthread_create() failed: " |
|||
"errno = %d\n", errno); |
|||
goto err; |
|||
} |
|||
} |
|||
|
|||
/* Wait for the threads to start */ |
|||
for (i = 0; i < n; i++) { |
|||
comp_thread_ctxt_t *thd = threads + i; |
|||
|
|||
while (thd->started == FALSE) |
|||
pthread_cond_wait(&thd->ctrl_cond, &thd->ctrl_mutex); |
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
} |
|||
|
|||
return threads; |
|||
|
|||
err: |
|||
return NULL; |
|||
} |
|||
|
|||
static |
|||
void |
|||
destroy_worker_threads(comp_thread_ctxt_t *threads, uint n) |
|||
{ |
|||
uint i; |
|||
|
|||
for (i = 0; i < n; i++) { |
|||
comp_thread_ctxt_t *thd = threads + i; |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
threads[i].cancelled = TRUE; |
|||
pthread_cond_signal(&thd->data_cond); |
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
|
|||
pthread_join(thd->id, NULL); |
|||
|
|||
pthread_cond_destroy(&thd->data_cond); |
|||
pthread_mutex_destroy(&thd->data_mutex); |
|||
pthread_cond_destroy(&thd->ctrl_cond); |
|||
pthread_mutex_destroy(&thd->ctrl_mutex); |
|||
|
|||
my_free(thd->to); |
|||
} |
|||
|
|||
my_free(threads); |
|||
} |
|||
|
|||
static |
|||
void * |
|||
compress_worker_thread_func(void *arg) |
|||
{ |
|||
comp_thread_ctxt_t *thd = (comp_thread_ctxt_t *) arg; |
|||
|
|||
pthread_mutex_lock(&thd->ctrl_mutex); |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
|
|||
thd->started = TRUE; |
|||
pthread_cond_signal(&thd->ctrl_cond); |
|||
|
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
|
|||
while (1) { |
|||
thd->data_avail = FALSE; |
|||
pthread_cond_signal(&thd->data_cond); |
|||
|
|||
while (!thd->data_avail && !thd->cancelled) { |
|||
pthread_cond_wait(&thd->data_cond, &thd->data_mutex); |
|||
} |
|||
|
|||
if (thd->cancelled) |
|||
break; |
|||
|
|||
thd->to_len = qlz_compress(thd->from, thd->to, thd->from_len, |
|||
&thd->state); |
|||
|
|||
/* qpress uses 0x00010000 as the initial value, but its own |
|||
Adler-32 implementation treats the value differently: |
|||
1. higher order bits are the sum of all bytes in the sequence |
|||
2. lower order bits are the sum of resulting values at every |
|||
step. |
|||
So it's the other way around as compared to zlib's adler32(). |
|||
That's why 0x00000001 is being passed here to be compatible |
|||
with qpress implementation. */ |
|||
|
|||
thd->adler = adler32(0x00000001, (uchar *) thd->to, |
|||
(uInt)thd->to_len); |
|||
} |
|||
|
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
|
|||
return NULL; |
|||
} |
@ -0,0 +1,28 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2011-2013 Percona LLC and/or its affiliates. |
|||
|
|||
Compression interface for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef DS_COMPRESS_H |
|||
#define DS_COMPRESS_H |
|||
|
|||
#include "datasink.h" |
|||
|
|||
extern datasink_t datasink_compress; |
|||
|
|||
#endif |
@ -0,0 +1,665 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2017 Percona LLC and/or its affiliates. |
|||
|
|||
Encryption datasink implementation for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
|
|||
#include <my_base.h> |
|||
#include "common.h" |
|||
#include "datasink.h" |
|||
#include "xbcrypt.h" |
|||
#include "xbcrypt_common.h" |
|||
#include "crc_glue.h" |
|||
|
|||
typedef struct { |
|||
pthread_t id; |
|||
uint num; |
|||
pthread_mutex_t ctrl_mutex; |
|||
pthread_cond_t ctrl_cond; |
|||
pthread_mutex_t data_mutex; |
|||
pthread_cond_t data_cond; |
|||
my_bool started; |
|||
my_bool data_avail; |
|||
my_bool cancelled; |
|||
my_bool failed; |
|||
const uchar *from; |
|||
size_t from_len; |
|||
uchar *to; |
|||
size_t to_len; |
|||
size_t to_size; |
|||
const uchar *iv; |
|||
size_t iv_len; |
|||
unsigned long long offset; |
|||
my_bool hash_appended; |
|||
gcry_cipher_hd_t cipher_handle; |
|||
xb_rcrypt_result_t parse_result; |
|||
} crypt_thread_ctxt_t; |
|||
|
|||
typedef struct { |
|||
crypt_thread_ctxt_t *threads; |
|||
uint nthreads; |
|||
int encrypt_algo; |
|||
size_t chunk_size; |
|||
char *encrypt_key; |
|||
char *encrypt_key_file; |
|||
} ds_decrypt_ctxt_t; |
|||
|
|||
typedef struct { |
|||
ds_decrypt_ctxt_t *crypt_ctxt; |
|||
size_t bytes_processed; |
|||
ds_file_t *dest_file; |
|||
uchar *buf; |
|||
size_t buf_len; |
|||
size_t buf_size; |
|||
} ds_decrypt_file_t; |
|||
|
|||
int ds_decrypt_encrypt_threads = 1; |
|||
|
|||
static ds_ctxt_t *decrypt_init(const char *root); |
|||
static ds_file_t *decrypt_open(ds_ctxt_t *ctxt, const char *path, |
|||
MY_STAT *mystat); |
|||
static int decrypt_write(ds_file_t *file, const void *buf, size_t len); |
|||
static int decrypt_close(ds_file_t *file); |
|||
static void decrypt_deinit(ds_ctxt_t *ctxt); |
|||
|
|||
datasink_t datasink_decrypt = { |
|||
&decrypt_init, |
|||
&decrypt_open, |
|||
&decrypt_write, |
|||
&decrypt_close, |
|||
&decrypt_deinit |
|||
}; |
|||
|
|||
static crypt_thread_ctxt_t *create_worker_threads(uint n); |
|||
static void destroy_worker_threads(crypt_thread_ctxt_t *threads, uint n); |
|||
static void *decrypt_worker_thread_func(void *arg); |
|||
|
|||
static |
|||
ds_ctxt_t * |
|||
decrypt_init(const char *root) |
|||
{ |
|||
ds_ctxt_t *ctxt; |
|||
ds_decrypt_ctxt_t *decrypt_ctxt; |
|||
crypt_thread_ctxt_t *threads; |
|||
|
|||
if (xb_crypt_init(NULL)) { |
|||
return NULL; |
|||
} |
|||
|
|||
/* Create and initialize the worker threads */ |
|||
threads = create_worker_threads(ds_decrypt_encrypt_threads); |
|||
if (threads == NULL) { |
|||
msg("decrypt: failed to create worker threads.\n"); |
|||
return NULL; |
|||
} |
|||
|
|||
ctxt = (ds_ctxt_t *) my_malloc(sizeof(ds_ctxt_t) + |
|||
sizeof(ds_decrypt_ctxt_t), |
|||
MYF(MY_FAE)); |
|||
|
|||
decrypt_ctxt = (ds_decrypt_ctxt_t *) (ctxt + 1); |
|||
decrypt_ctxt->threads = threads; |
|||
decrypt_ctxt->nthreads = ds_decrypt_encrypt_threads; |
|||
|
|||
ctxt->ptr = decrypt_ctxt; |
|||
ctxt->root = my_strdup(root, MYF(MY_FAE)); |
|||
|
|||
return ctxt; |
|||
} |
|||
|
|||
static |
|||
ds_file_t * |
|||
decrypt_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) |
|||
{ |
|||
ds_ctxt_t *dest_ctxt; |
|||
|
|||
ds_decrypt_ctxt_t *crypt_ctxt; |
|||
ds_decrypt_file_t *crypt_file; |
|||
|
|||
char new_name[FN_REFLEN]; |
|||
ds_file_t *file; |
|||
|
|||
xb_ad(ctxt->pipe_ctxt != NULL); |
|||
dest_ctxt = ctxt->pipe_ctxt; |
|||
|
|||
crypt_ctxt = (ds_decrypt_ctxt_t *) ctxt->ptr; |
|||
|
|||
|
|||
file = (ds_file_t *) my_malloc(sizeof(ds_file_t) + |
|||
sizeof(ds_decrypt_file_t), |
|||
MYF(MY_FAE|MY_ZEROFILL)); |
|||
|
|||
crypt_file = (ds_decrypt_file_t *) (file + 1); |
|||
|
|||
/* Remove the .xbcrypt extension from the filename */ |
|||
strncpy(new_name, path, FN_REFLEN); |
|||
new_name[strlen(new_name) - 8] = 0; |
|||
crypt_file->dest_file = ds_open(dest_ctxt, new_name, mystat); |
|||
if (crypt_file->dest_file == NULL) { |
|||
msg("decrypt: ds_open(\"%s\") failed.\n", new_name); |
|||
goto err; |
|||
} |
|||
|
|||
crypt_file->crypt_ctxt = crypt_ctxt; |
|||
crypt_file->buf = NULL; |
|||
crypt_file->buf_size = 0; |
|||
crypt_file->buf_len = 0; |
|||
|
|||
file->ptr = crypt_file; |
|||
file->path = crypt_file->dest_file->path; |
|||
|
|||
return file; |
|||
|
|||
err: |
|||
if (crypt_file->dest_file) { |
|||
ds_close(crypt_file->dest_file); |
|||
} |
|||
my_free(file); |
|||
return NULL; |
|||
} |
|||
|
|||
#define CHECK_BUF_SIZE(ptr, size, buf, len) \ |
|||
if (ptr + size - buf > (ssize_t) len) { \ |
|||
result = XB_CRYPT_READ_INCOMPLETE; \ |
|||
goto exit; \ |
|||
} |
|||
|
|||
static |
|||
xb_rcrypt_result_t |
|||
parse_xbcrypt_chunk(crypt_thread_ctxt_t *thd, const uchar *buf, size_t len, |
|||
size_t *bytes_processed) |
|||
{ |
|||
const uchar *ptr; |
|||
uint version; |
|||
ulong checksum, checksum_exp; |
|||
ulonglong tmp; |
|||
xb_rcrypt_result_t result = XB_CRYPT_READ_CHUNK; |
|||
|
|||
*bytes_processed = 0; |
|||
ptr = buf; |
|||
|
|||
CHECK_BUF_SIZE(ptr, XB_CRYPT_CHUNK_MAGIC_SIZE, buf, len); |
|||
if (memcmp(ptr, XB_CRYPT_CHUNK_MAGIC3, |
|||
XB_CRYPT_CHUNK_MAGIC_SIZE) == 0) { |
|||
version = 3; |
|||
} else if (memcmp(ptr, XB_CRYPT_CHUNK_MAGIC2, |
|||
XB_CRYPT_CHUNK_MAGIC_SIZE) == 0) { |
|||
version = 2; |
|||
} else if (memcmp(ptr, XB_CRYPT_CHUNK_MAGIC1, |
|||
XB_CRYPT_CHUNK_MAGIC_SIZE) == 0) { |
|||
version = 1; |
|||
} else { |
|||
msg("%s:%s: wrong chunk magic at offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, thd->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto exit; |
|||
} |
|||
|
|||
ptr += XB_CRYPT_CHUNK_MAGIC_SIZE; |
|||
thd->offset += XB_CRYPT_CHUNK_MAGIC_SIZE; |
|||
|
|||
CHECK_BUF_SIZE(ptr, 8, buf, len); |
|||
tmp = uint8korr(ptr); /* reserved */ |
|||
ptr += 8; |
|||
thd->offset += 8; |
|||
|
|||
CHECK_BUF_SIZE(ptr, 8, buf, len); |
|||
tmp = uint8korr(ptr); /* original size */ |
|||
ptr += 8; |
|||
if (tmp > INT_MAX) { |
|||
msg("%s:%s: invalid original size at offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, thd->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto exit; |
|||
} |
|||
thd->offset += 8; |
|||
thd->to_len = (size_t)tmp; |
|||
|
|||
if (thd->to_size < thd->to_len + XB_CRYPT_HASH_LEN) { |
|||
thd->to = (uchar *) my_realloc( |
|||
thd->to, |
|||
thd->to_len + XB_CRYPT_HASH_LEN, |
|||
MYF(MY_FAE | MY_ALLOW_ZERO_PTR)); |
|||
thd->to_size = thd->to_len; |
|||
} |
|||
|
|||
CHECK_BUF_SIZE(ptr, 8, buf, len); |
|||
tmp = uint8korr(ptr); /* encrypted size */ |
|||
ptr += 8; |
|||
if (tmp > INT_MAX) { |
|||
msg("%s:%s: invalid encrypted size at offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, thd->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto exit; |
|||
} |
|||
thd->offset += 8; |
|||
thd->from_len = (size_t)tmp; |
|||
|
|||
xb_a(thd->from_len <= thd->to_len + XB_CRYPT_HASH_LEN); |
|||
|
|||
CHECK_BUF_SIZE(ptr, 4, buf, len); |
|||
checksum_exp = uint4korr(ptr); /* checksum */ |
|||
ptr += 4; |
|||
thd->offset += 4; |
|||
|
|||
/* iv size */ |
|||
if (version == 1) { |
|||
thd->iv_len = 0; |
|||
thd->iv = NULL; |
|||
} else { |
|||
CHECK_BUF_SIZE(ptr, 8, buf, len); |
|||
|
|||
tmp = uint8korr(ptr); |
|||
if (tmp > INT_MAX) { |
|||
msg("%s:%s: invalid iv size at offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, thd->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto exit; |
|||
} |
|||
ptr += 8; |
|||
thd->offset += 8; |
|||
thd->iv_len = (size_t)tmp; |
|||
} |
|||
|
|||
if (thd->iv_len > 0) { |
|||
CHECK_BUF_SIZE(ptr, thd->iv_len, buf, len); |
|||
thd->iv = ptr; |
|||
ptr += thd->iv_len; |
|||
} |
|||
|
|||
/* for version euqals 2 we need to read in the iv data but do not init |
|||
CTR with it */ |
|||
if (version == 2) { |
|||
thd->iv_len = 0; |
|||
thd->iv = 0; |
|||
} |
|||
|
|||
if (thd->from_len > 0) { |
|||
CHECK_BUF_SIZE(ptr, thd->from_len, buf, len); |
|||
thd->from = ptr; |
|||
ptr += thd->from_len; |
|||
} |
|||
|
|||
xb_ad(thd->from_len <= thd->to_len); |
|||
|
|||
checksum = crc32_iso3309(0, thd->from, thd->from_len); |
|||
if (checksum != checksum_exp) { |
|||
msg("%s:%s invalid checksum at offset 0x%llx, " |
|||
"expected 0x%lx, actual 0x%lx.\n", my_progname, |
|||
__FUNCTION__, thd->offset, checksum_exp, checksum); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto exit; |
|||
} |
|||
|
|||
thd->offset += thd->from_len; |
|||
|
|||
thd->hash_appended = version > 2; |
|||
|
|||
exit: |
|||
|
|||
*bytes_processed = (size_t) (ptr - buf); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
static |
|||
int |
|||
decrypt_write(ds_file_t *file, const void *buf, size_t len) |
|||
{ |
|||
ds_decrypt_file_t *crypt_file; |
|||
ds_decrypt_ctxt_t *crypt_ctxt; |
|||
crypt_thread_ctxt_t *threads; |
|||
crypt_thread_ctxt_t *thd; |
|||
uint nthreads; |
|||
uint i; |
|||
size_t bytes_processed; |
|||
xb_rcrypt_result_t parse_result = XB_CRYPT_READ_CHUNK; |
|||
my_bool err = FALSE; |
|||
|
|||
crypt_file = (ds_decrypt_file_t *) file->ptr; |
|||
crypt_ctxt = crypt_file->crypt_ctxt; |
|||
|
|||
threads = crypt_ctxt->threads; |
|||
nthreads = crypt_ctxt->nthreads; |
|||
|
|||
if (crypt_file->buf_len > 0) { |
|||
thd = threads; |
|||
|
|||
pthread_mutex_lock(&thd->ctrl_mutex); |
|||
|
|||
do { |
|||
if (parse_result == XB_CRYPT_READ_INCOMPLETE) { |
|||
crypt_file->buf_size = crypt_file->buf_size * 2; |
|||
crypt_file->buf = (uchar *) my_realloc( |
|||
crypt_file->buf, |
|||
crypt_file->buf_size, |
|||
MYF(MY_FAE|MY_ALLOW_ZERO_PTR)); |
|||
} |
|||
|
|||
memcpy(crypt_file->buf + crypt_file->buf_len, |
|||
buf, MY_MIN(crypt_file->buf_size - |
|||
crypt_file->buf_len, len)); |
|||
|
|||
parse_result = parse_xbcrypt_chunk( |
|||
thd, crypt_file->buf, |
|||
crypt_file->buf_size, &bytes_processed); |
|||
|
|||
if (parse_result == XB_CRYPT_READ_ERROR) { |
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
return 1; |
|||
} |
|||
|
|||
} while (parse_result == XB_CRYPT_READ_INCOMPLETE && |
|||
crypt_file->buf_size < len); |
|||
|
|||
if (parse_result != XB_CRYPT_READ_CHUNK) { |
|||
msg("decrypt: incomplete data.\n"); |
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
return 1; |
|||
} |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
thd->data_avail = TRUE; |
|||
pthread_cond_signal(&thd->data_cond); |
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
|
|||
len -= bytes_processed - crypt_file->buf_len; |
|||
buf += bytes_processed - crypt_file->buf_len; |
|||
|
|||
/* reap */ |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
while (thd->data_avail == TRUE) { |
|||
pthread_cond_wait(&thd->data_cond, |
|||
&thd->data_mutex); |
|||
} |
|||
|
|||
if (thd->failed) { |
|||
msg("decrypt: failed to decrypt chunk.\n"); |
|||
err = TRUE; |
|||
} |
|||
|
|||
xb_a(thd->to_len > 0); |
|||
|
|||
if (!err && |
|||
ds_write(crypt_file->dest_file, thd->to, thd->to_len)) { |
|||
msg("decrypt: write to destination failed.\n"); |
|||
err = TRUE; |
|||
} |
|||
|
|||
crypt_file->bytes_processed += thd->from_len; |
|||
|
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
|
|||
crypt_file->buf_len = 0; |
|||
|
|||
if (err) { |
|||
return 1; |
|||
} |
|||
} |
|||
|
|||
while (parse_result == XB_CRYPT_READ_CHUNK && len > 0) { |
|||
uint max_thread; |
|||
|
|||
for (i = 0; i < nthreads; i++) { |
|||
thd = threads + i; |
|||
|
|||
pthread_mutex_lock(&thd->ctrl_mutex); |
|||
|
|||
parse_result = parse_xbcrypt_chunk( |
|||
thd, buf, len, &bytes_processed); |
|||
|
|||
if (parse_result == XB_CRYPT_READ_ERROR) { |
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
err = TRUE; |
|||
break; |
|||
} |
|||
|
|||
thd->parse_result = parse_result; |
|||
|
|||
if (parse_result != XB_CRYPT_READ_CHUNK) { |
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
break; |
|||
} |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
thd->data_avail = TRUE; |
|||
pthread_cond_signal(&thd->data_cond); |
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
|
|||
len -= bytes_processed; |
|||
buf += bytes_processed; |
|||
} |
|||
|
|||
max_thread = (i < nthreads) ? i : nthreads - 1; |
|||
|
|||
/* Reap and write decrypted data */ |
|||
for (i = 0; i <= max_thread; i++) { |
|||
thd = threads + i; |
|||
|
|||
if (thd->parse_result != XB_CRYPT_READ_CHUNK) { |
|||
break; |
|||
} |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
while (thd->data_avail == TRUE) { |
|||
pthread_cond_wait(&thd->data_cond, |
|||
&thd->data_mutex); |
|||
} |
|||
|
|||
if (thd->failed) { |
|||
msg("decrypt: failed to decrypt chunk.\n"); |
|||
err = TRUE; |
|||
} |
|||
|
|||
xb_a(thd->to_len > 0); |
|||
|
|||
if (!err && ds_write(crypt_file->dest_file, thd->to, |
|||
thd->to_len)) { |
|||
msg("decrypt: write to destination failed.\n"); |
|||
err = TRUE; |
|||
} |
|||
|
|||
crypt_file->bytes_processed += thd->from_len; |
|||
|
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
} |
|||
|
|||
if (err) { |
|||
return 1; |
|||
} |
|||
} |
|||
|
|||
if (parse_result == XB_CRYPT_READ_INCOMPLETE && len > 0) { |
|||
crypt_file->buf_len = len; |
|||
if (crypt_file->buf_size < len) { |
|||
crypt_file->buf = (uchar *) my_realloc( |
|||
crypt_file->buf, |
|||
crypt_file->buf_len, |
|||
MYF(MY_FAE | MY_ALLOW_ZERO_PTR)); |
|||
crypt_file->buf_size = len; |
|||
} |
|||
memcpy(crypt_file->buf, buf, len); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static |
|||
int |
|||
decrypt_close(ds_file_t *file) |
|||
{ |
|||
ds_decrypt_file_t *crypt_file; |
|||
ds_file_t *dest_file; |
|||
int rc = 0; |
|||
|
|||
crypt_file = (ds_decrypt_file_t *) file->ptr; |
|||
dest_file = crypt_file->dest_file; |
|||
|
|||
if (ds_close(dest_file)) { |
|||
rc = 1; |
|||
} |
|||
|
|||
my_free(crypt_file->buf); |
|||
my_free(file); |
|||
|
|||
return rc; |
|||
} |
|||
|
|||
static |
|||
void |
|||
decrypt_deinit(ds_ctxt_t *ctxt) |
|||
{ |
|||
ds_decrypt_ctxt_t *crypt_ctxt; |
|||
|
|||
xb_ad(ctxt->pipe_ctxt != NULL); |
|||
|
|||
crypt_ctxt = (ds_decrypt_ctxt_t *) ctxt->ptr; |
|||
|
|||
destroy_worker_threads(crypt_ctxt->threads, crypt_ctxt->nthreads); |
|||
|
|||
my_free(ctxt->root); |
|||
my_free(ctxt); |
|||
} |
|||
|
|||
static |
|||
crypt_thread_ctxt_t * |
|||
create_worker_threads(uint n) |
|||
{ |
|||
crypt_thread_ctxt_t *threads; |
|||
uint i; |
|||
|
|||
threads = (crypt_thread_ctxt_t *) |
|||
my_malloc(sizeof(crypt_thread_ctxt_t) * n, |
|||
MYF(MY_FAE | MY_ZEROFILL)); |
|||
|
|||
for (i = 0; i < n; i++) { |
|||
crypt_thread_ctxt_t *thd = threads + i; |
|||
|
|||
thd->num = i + 1; |
|||
|
|||
/* Initialize the control mutex and condition var */ |
|||
if (pthread_mutex_init(&thd->ctrl_mutex, NULL) || |
|||
pthread_cond_init(&thd->ctrl_cond, NULL)) { |
|||
goto err; |
|||
} |
|||
|
|||
/* Initialize and data mutex and condition var */ |
|||
if (pthread_mutex_init(&thd->data_mutex, NULL) || |
|||
pthread_cond_init(&thd->data_cond, NULL)) { |
|||
goto err; |
|||
} |
|||
|
|||
xb_crypt_cipher_open(&thd->cipher_handle); |
|||
|
|||
pthread_mutex_lock(&thd->ctrl_mutex); |
|||
|
|||
if (pthread_create(&thd->id, NULL, decrypt_worker_thread_func, |
|||
thd)) { |
|||
msg("decrypt: pthread_create() failed: " |
|||
"errno = %d\n", errno); |
|||
goto err; |
|||
} |
|||
} |
|||
|
|||
/* Wait for the threads to start */ |
|||
for (i = 0; i < n; i++) { |
|||
crypt_thread_ctxt_t *thd = threads + i; |
|||
|
|||
while (thd->started == FALSE) |
|||
pthread_cond_wait(&thd->ctrl_cond, &thd->ctrl_mutex); |
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
} |
|||
|
|||
return threads; |
|||
|
|||
err: |
|||
return NULL; |
|||
} |
|||
|
|||
static |
|||
void |
|||
destroy_worker_threads(crypt_thread_ctxt_t *threads, uint n) |
|||
{ |
|||
uint i; |
|||
|
|||
for (i = 0; i < n; i++) { |
|||
crypt_thread_ctxt_t *thd = threads + i; |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
threads[i].cancelled = TRUE; |
|||
pthread_cond_signal(&thd->data_cond); |
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
|
|||
pthread_join(thd->id, NULL); |
|||
|
|||
pthread_cond_destroy(&thd->data_cond); |
|||
pthread_mutex_destroy(&thd->data_mutex); |
|||
pthread_cond_destroy(&thd->ctrl_cond); |
|||
pthread_mutex_destroy(&thd->ctrl_mutex); |
|||
|
|||
xb_crypt_cipher_close(thd->cipher_handle); |
|||
|
|||
my_free(thd->to); |
|||
} |
|||
|
|||
my_free(threads); |
|||
} |
|||
|
|||
static |
|||
void * |
|||
decrypt_worker_thread_func(void *arg) |
|||
{ |
|||
crypt_thread_ctxt_t *thd = (crypt_thread_ctxt_t *) arg; |
|||
|
|||
pthread_mutex_lock(&thd->ctrl_mutex); |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
|
|||
thd->started = TRUE; |
|||
pthread_cond_signal(&thd->ctrl_cond); |
|||
|
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
|
|||
while (1) { |
|||
thd->data_avail = FALSE; |
|||
pthread_cond_signal(&thd->data_cond); |
|||
|
|||
while (!thd->data_avail && !thd->cancelled) { |
|||
pthread_cond_wait(&thd->data_cond, &thd->data_mutex); |
|||
} |
|||
|
|||
if (thd->cancelled) |
|||
break; |
|||
|
|||
if (xb_crypt_decrypt(thd->cipher_handle, thd->from, |
|||
thd->from_len, thd->to, &thd->to_len, |
|||
thd->iv, thd->iv_len, |
|||
thd->hash_appended)) { |
|||
thd->failed = TRUE; |
|||
continue; |
|||
} |
|||
|
|||
} |
|||
|
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
|
|||
return NULL; |
|||
} |
@ -0,0 +1,30 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2017 Percona LLC and/or its affiliates. |
|||
|
|||
Encryption interface for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef DS_DECRYPT_H |
|||
#define DS_DECRYPT_H |
|||
|
|||
#include "datasink.h" |
|||
|
|||
extern datasink_t datasink_decrypt; |
|||
|
|||
extern int ds_decrypt_encrypt_threads; |
|||
|
|||
#endif |
@ -0,0 +1,446 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2013 Percona LLC and/or its affiliates. |
|||
|
|||
Encryption datasink implementation for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
|
|||
#include <my_base.h> |
|||
#include "common.h" |
|||
#include "datasink.h" |
|||
#include "xbcrypt_common.h" |
|||
#ifdef HAVE_GRYPT |
|||
#include "xbcrypt.h" |
|||
|
|||
#define XB_CRYPT_CHUNK_SIZE ((size_t) (ds_encrypt_encrypt_chunk_size)) |
|||
|
|||
typedef struct { |
|||
pthread_t id; |
|||
uint num; |
|||
pthread_mutex_t ctrl_mutex; |
|||
pthread_cond_t ctrl_cond; |
|||
pthread_mutex_t data_mutex; |
|||
pthread_cond_t data_cond; |
|||
my_bool started; |
|||
my_bool data_avail; |
|||
my_bool cancelled; |
|||
const uchar *from; |
|||
size_t from_len; |
|||
uchar *to; |
|||
uchar *iv; |
|||
size_t to_len; |
|||
gcry_cipher_hd_t cipher_handle; |
|||
} crypt_thread_ctxt_t; |
|||
|
|||
typedef struct { |
|||
crypt_thread_ctxt_t *threads; |
|||
uint nthreads; |
|||
} ds_encrypt_ctxt_t; |
|||
|
|||
typedef struct { |
|||
xb_wcrypt_t *xbcrypt_file; |
|||
ds_encrypt_ctxt_t *crypt_ctxt; |
|||
size_t bytes_processed; |
|||
ds_file_t *dest_file; |
|||
} ds_encrypt_file_t; |
|||
|
|||
/* Encryption options */ |
|||
uint ds_encrypt_encrypt_threads; |
|||
ulonglong ds_encrypt_encrypt_chunk_size; |
|||
|
|||
static ds_ctxt_t *encrypt_init(const char *root); |
|||
static ds_file_t *encrypt_open(ds_ctxt_t *ctxt, const char *path, |
|||
MY_STAT *mystat); |
|||
static int encrypt_write(ds_file_t *file, const void *buf, size_t len); |
|||
static int encrypt_close(ds_file_t *file); |
|||
static void encrypt_deinit(ds_ctxt_t *ctxt); |
|||
|
|||
datasink_t datasink_encrypt = { |
|||
&encrypt_init, |
|||
&encrypt_open, |
|||
&encrypt_write, |
|||
&encrypt_close, |
|||
&encrypt_deinit |
|||
}; |
|||
|
|||
static crypt_thread_ctxt_t *create_worker_threads(uint n); |
|||
static void destroy_worker_threads(crypt_thread_ctxt_t *threads, uint n); |
|||
static void *encrypt_worker_thread_func(void *arg); |
|||
|
|||
static uint encrypt_iv_len = 0; |
|||
|
|||
static |
|||
ssize_t |
|||
my_xb_crypt_write_callback(void *userdata, const void *buf, size_t len) |
|||
{ |
|||
ds_encrypt_file_t *encrypt_file; |
|||
|
|||
encrypt_file = (ds_encrypt_file_t *) userdata; |
|||
|
|||
xb_ad(encrypt_file != NULL); |
|||
xb_ad(encrypt_file->dest_file != NULL); |
|||
|
|||
if (!ds_write(encrypt_file->dest_file, buf, len)) { |
|||
return len; |
|||
} |
|||
return -1; |
|||
} |
|||
|
|||
static |
|||
ds_ctxt_t * |
|||
encrypt_init(const char *root) |
|||
{ |
|||
ds_ctxt_t *ctxt; |
|||
ds_encrypt_ctxt_t *encrypt_ctxt; |
|||
crypt_thread_ctxt_t *threads; |
|||
|
|||
if (xb_crypt_init(&encrypt_iv_len)) { |
|||
return NULL; |
|||
} |
|||
|
|||
/* Create and initialize the worker threads */ |
|||
threads = create_worker_threads(ds_encrypt_encrypt_threads); |
|||
if (threads == NULL) { |
|||
msg("encrypt: failed to create worker threads.\n"); |
|||
return NULL; |
|||
} |
|||
|
|||
ctxt = (ds_ctxt_t *) my_malloc(sizeof(ds_ctxt_t) + |
|||
sizeof(ds_encrypt_ctxt_t), |
|||
MYF(MY_FAE)); |
|||
|
|||
encrypt_ctxt = (ds_encrypt_ctxt_t *) (ctxt + 1); |
|||
encrypt_ctxt->threads = threads; |
|||
encrypt_ctxt->nthreads = ds_encrypt_encrypt_threads; |
|||
|
|||
ctxt->ptr = encrypt_ctxt; |
|||
ctxt->root = my_strdup(root, MYF(MY_FAE)); |
|||
|
|||
return ctxt; |
|||
} |
|||
|
|||
static |
|||
ds_file_t * |
|||
encrypt_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) |
|||
{ |
|||
ds_ctxt_t *dest_ctxt; |
|||
|
|||
ds_encrypt_ctxt_t *crypt_ctxt; |
|||
ds_encrypt_file_t *crypt_file; |
|||
|
|||
char new_name[FN_REFLEN]; |
|||
ds_file_t *file; |
|||
|
|||
xb_ad(ctxt->pipe_ctxt != NULL); |
|||
dest_ctxt = ctxt->pipe_ctxt; |
|||
|
|||
crypt_ctxt = (ds_encrypt_ctxt_t *) ctxt->ptr; |
|||
|
|||
|
|||
file = (ds_file_t *) my_malloc(sizeof(ds_file_t) + |
|||
sizeof(ds_encrypt_file_t), |
|||
MYF(MY_FAE|MY_ZEROFILL)); |
|||
|
|||
crypt_file = (ds_encrypt_file_t *) (file + 1); |
|||
|
|||
/* Append the .xbcrypt extension to the filename */ |
|||
fn_format(new_name, path, "", ".xbcrypt", MYF(MY_APPEND_EXT)); |
|||
crypt_file->dest_file = ds_open(dest_ctxt, new_name, mystat); |
|||
if (crypt_file->dest_file == NULL) { |
|||
msg("encrypt: ds_open(\"%s\") failed.\n", new_name); |
|||
goto err; |
|||
} |
|||
|
|||
crypt_file->crypt_ctxt = crypt_ctxt; |
|||
crypt_file->xbcrypt_file = xb_crypt_write_open(crypt_file, |
|||
my_xb_crypt_write_callback); |
|||
|
|||
if (crypt_file->xbcrypt_file == NULL) { |
|||
msg("encrypt: xb_crypt_write_open() failed.\n"); |
|||
goto err; |
|||
} |
|||
|
|||
|
|||
file->ptr = crypt_file; |
|||
file->path = crypt_file->dest_file->path; |
|||
|
|||
return file; |
|||
|
|||
err: |
|||
if (crypt_file->dest_file) { |
|||
ds_close(crypt_file->dest_file); |
|||
} |
|||
my_free(file); |
|||
return NULL; |
|||
} |
|||
|
|||
static |
|||
int |
|||
encrypt_write(ds_file_t *file, const void *buf, size_t len) |
|||
{ |
|||
ds_encrypt_file_t *crypt_file; |
|||
ds_encrypt_ctxt_t *crypt_ctxt; |
|||
crypt_thread_ctxt_t *threads; |
|||
crypt_thread_ctxt_t *thd; |
|||
uint nthreads; |
|||
uint i; |
|||
const uchar *ptr; |
|||
|
|||
crypt_file = (ds_encrypt_file_t *) file->ptr; |
|||
crypt_ctxt = crypt_file->crypt_ctxt; |
|||
|
|||
threads = crypt_ctxt->threads; |
|||
nthreads = crypt_ctxt->nthreads; |
|||
|
|||
ptr = (const uchar *) buf; |
|||
while (len > 0) { |
|||
uint max_thread; |
|||
|
|||
/* Send data to worker threads for encryption */ |
|||
for (i = 0; i < nthreads; i++) { |
|||
size_t chunk_len; |
|||
|
|||
thd = threads + i; |
|||
|
|||
pthread_mutex_lock(&thd->ctrl_mutex); |
|||
|
|||
chunk_len = (len > XB_CRYPT_CHUNK_SIZE) ? |
|||
XB_CRYPT_CHUNK_SIZE : len; |
|||
thd->from = ptr; |
|||
thd->from_len = chunk_len; |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
thd->data_avail = TRUE; |
|||
pthread_cond_signal(&thd->data_cond); |
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
|
|||
len -= chunk_len; |
|||
if (len == 0) { |
|||
break; |
|||
} |
|||
ptr += chunk_len; |
|||
} |
|||
|
|||
max_thread = (i < nthreads) ? i : nthreads - 1; |
|||
|
|||
/* Reap and stream the encrypted data */ |
|||
for (i = 0; i <= max_thread; i++) { |
|||
thd = threads + i; |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
while (thd->data_avail == TRUE) { |
|||
pthread_cond_wait(&thd->data_cond, |
|||
&thd->data_mutex); |
|||
} |
|||
|
|||
xb_a(threads[i].to_len > 0); |
|||
|
|||
if (xb_crypt_write_chunk(crypt_file->xbcrypt_file, |
|||
threads[i].to, |
|||
threads[i].from_len + |
|||
XB_CRYPT_HASH_LEN, |
|||
threads[i].to_len, |
|||
threads[i].iv, |
|||
encrypt_iv_len)) { |
|||
msg("encrypt: write to the destination file " |
|||
"failed.\n"); |
|||
return 1; |
|||
} |
|||
|
|||
crypt_file->bytes_processed += threads[i].from_len; |
|||
|
|||
pthread_mutex_unlock(&threads[i].data_mutex); |
|||
pthread_mutex_unlock(&threads[i].ctrl_mutex); |
|||
} |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static |
|||
int |
|||
encrypt_close(ds_file_t *file) |
|||
{ |
|||
ds_encrypt_file_t *crypt_file; |
|||
ds_file_t *dest_file; |
|||
int rc = 0; |
|||
|
|||
crypt_file = (ds_encrypt_file_t *) file->ptr; |
|||
dest_file = crypt_file->dest_file; |
|||
|
|||
rc = xb_crypt_write_close(crypt_file->xbcrypt_file); |
|||
|
|||
if (ds_close(dest_file)) { |
|||
rc = 1; |
|||
} |
|||
|
|||
my_free(file); |
|||
|
|||
return rc; |
|||
} |
|||
|
|||
static |
|||
void |
|||
encrypt_deinit(ds_ctxt_t *ctxt) |
|||
{ |
|||
ds_encrypt_ctxt_t *crypt_ctxt; |
|||
|
|||
xb_ad(ctxt->pipe_ctxt != NULL); |
|||
|
|||
crypt_ctxt = (ds_encrypt_ctxt_t *) ctxt->ptr; |
|||
|
|||
destroy_worker_threads(crypt_ctxt->threads, crypt_ctxt->nthreads); |
|||
|
|||
my_free(ctxt->root); |
|||
my_free(ctxt); |
|||
} |
|||
|
|||
static |
|||
crypt_thread_ctxt_t * |
|||
create_worker_threads(uint n) |
|||
{ |
|||
crypt_thread_ctxt_t *threads; |
|||
uint i; |
|||
|
|||
threads = (crypt_thread_ctxt_t *) |
|||
my_malloc(sizeof(crypt_thread_ctxt_t) * n, MYF(MY_FAE)); |
|||
|
|||
for (i = 0; i < n; i++) { |
|||
crypt_thread_ctxt_t *thd = threads + i; |
|||
|
|||
thd->num = i + 1; |
|||
thd->started = FALSE; |
|||
thd->cancelled = FALSE; |
|||
thd->data_avail = FALSE; |
|||
|
|||
thd->to = (uchar *) my_malloc(XB_CRYPT_CHUNK_SIZE + |
|||
XB_CRYPT_HASH_LEN, MYF(MY_FAE)); |
|||
|
|||
thd->iv = (uchar *) my_malloc(encrypt_iv_len, MYF(MY_FAE)); |
|||
|
|||
/* Initialize the control mutex and condition var */ |
|||
if (pthread_mutex_init(&thd->ctrl_mutex, NULL) || |
|||
pthread_cond_init(&thd->ctrl_cond, NULL)) { |
|||
goto err; |
|||
} |
|||
|
|||
/* Initialize and data mutex and condition var */ |
|||
if (pthread_mutex_init(&thd->data_mutex, NULL) || |
|||
pthread_cond_init(&thd->data_cond, NULL)) { |
|||
goto err; |
|||
} |
|||
|
|||
if (xb_crypt_cipher_open(&thd->cipher_handle)) { |
|||
goto err; |
|||
} |
|||
|
|||
pthread_mutex_lock(&thd->ctrl_mutex); |
|||
|
|||
if (pthread_create(&thd->id, NULL, encrypt_worker_thread_func, |
|||
thd)) { |
|||
msg("encrypt: pthread_create() failed: " |
|||
"errno = %d\n", errno); |
|||
goto err; |
|||
} |
|||
} |
|||
|
|||
/* Wait for the threads to start */ |
|||
for (i = 0; i < n; i++) { |
|||
crypt_thread_ctxt_t *thd = threads + i; |
|||
|
|||
while (thd->started == FALSE) |
|||
pthread_cond_wait(&thd->ctrl_cond, &thd->ctrl_mutex); |
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
} |
|||
|
|||
return threads; |
|||
|
|||
err: |
|||
return NULL; |
|||
} |
|||
|
|||
static |
|||
void |
|||
destroy_worker_threads(crypt_thread_ctxt_t *threads, uint n) |
|||
{ |
|||
uint i; |
|||
|
|||
for (i = 0; i < n; i++) { |
|||
crypt_thread_ctxt_t *thd = threads + i; |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
threads[i].cancelled = TRUE; |
|||
pthread_cond_signal(&thd->data_cond); |
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
|
|||
pthread_join(thd->id, NULL); |
|||
|
|||
pthread_cond_destroy(&thd->data_cond); |
|||
pthread_mutex_destroy(&thd->data_mutex); |
|||
pthread_cond_destroy(&thd->ctrl_cond); |
|||
pthread_mutex_destroy(&thd->ctrl_mutex); |
|||
|
|||
xb_crypt_cipher_close(thd->cipher_handle); |
|||
|
|||
my_free(thd->to); |
|||
my_free(thd->iv); |
|||
} |
|||
|
|||
my_free(threads); |
|||
} |
|||
|
|||
static |
|||
void * |
|||
encrypt_worker_thread_func(void *arg) |
|||
{ |
|||
crypt_thread_ctxt_t *thd = (crypt_thread_ctxt_t *) arg; |
|||
|
|||
pthread_mutex_lock(&thd->ctrl_mutex); |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
|
|||
thd->started = TRUE; |
|||
pthread_cond_signal(&thd->ctrl_cond); |
|||
|
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
|
|||
while (1) { |
|||
thd->data_avail = FALSE; |
|||
pthread_cond_signal(&thd->data_cond); |
|||
|
|||
while (!thd->data_avail && !thd->cancelled) { |
|||
pthread_cond_wait(&thd->data_cond, &thd->data_mutex); |
|||
} |
|||
|
|||
if (thd->cancelled) |
|||
break; |
|||
|
|||
thd->to_len = thd->from_len; |
|||
|
|||
if (xb_crypt_encrypt(thd->cipher_handle, thd->from, |
|||
thd->from_len, thd->to, &thd->to_len, |
|||
thd->iv)) { |
|||
thd->to_len = 0; |
|||
continue; |
|||
} |
|||
} |
|||
|
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
|
|||
return NULL; |
|||
} |
|||
#endif /* HAVE_GCRYPT*/ |
@ -0,0 +1,33 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2013 Percona LLC and/or its affiliates. |
|||
|
|||
Encryption interface for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef DS_ENCRYPT_H |
|||
#define DS_ENCRYPT_H |
|||
|
|||
#include "datasink.h" |
|||
#ifdef HAVE_GCRYPT |
|||
extern datasink_t datasink_encrypt; |
|||
#endif |
|||
/* Encryption options */ |
|||
extern uint ds_encrypt_encrypt_threads; |
|||
extern ulonglong ds_encrypt_encrypt_chunk_size; |
|||
|
|||
|
|||
#endif |
@ -0,0 +1,151 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2011-2013 Percona LLC and/or its affiliates. |
|||
|
|||
Local datasink implementation for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include <mysql_version.h> |
|||
#include <my_base.h> |
|||
#include <mysys_err.h> |
|||
#include "common.h" |
|||
#include "datasink.h" |
|||
|
|||
typedef struct { |
|||
File fd; |
|||
} ds_local_file_t; |
|||
|
|||
static ds_ctxt_t *local_init(const char *root); |
|||
static ds_file_t *local_open(ds_ctxt_t *ctxt, const char *path, |
|||
MY_STAT *mystat); |
|||
static int local_write(ds_file_t *file, const void *buf, size_t len); |
|||
static int local_close(ds_file_t *file); |
|||
static void local_deinit(ds_ctxt_t *ctxt); |
|||
|
|||
datasink_t datasink_local = { |
|||
&local_init, |
|||
&local_open, |
|||
&local_write, |
|||
&local_close, |
|||
&local_deinit |
|||
}; |
|||
|
|||
static |
|||
ds_ctxt_t * |
|||
local_init(const char *root) |
|||
{ |
|||
ds_ctxt_t *ctxt; |
|||
|
|||
if (my_mkdir(root, 0777, MYF(0)) < 0 |
|||
&& my_errno != EEXIST && my_errno != EISDIR) |
|||
{ |
|||
char errbuf[MYSYS_STRERROR_SIZE]; |
|||
my_strerror(errbuf, sizeof(errbuf),my_errno); |
|||
my_error(EE_CANT_MKDIR, MYF(ME_BELL | ME_WAITTANG), |
|||
root, my_errno,errbuf, my_errno); |
|||
return NULL; |
|||
} |
|||
|
|||
ctxt = my_malloc(sizeof(ds_ctxt_t), MYF(MY_FAE)); |
|||
|
|||
ctxt->root = my_strdup(root, MYF(MY_FAE)); |
|||
|
|||
return ctxt; |
|||
} |
|||
|
|||
static |
|||
ds_file_t * |
|||
local_open(ds_ctxt_t *ctxt, const char *path, |
|||
MY_STAT *mystat __attribute__((unused))) |
|||
{ |
|||
char fullpath[FN_REFLEN]; |
|||
char dirpath[FN_REFLEN]; |
|||
size_t dirpath_len; |
|||
size_t path_len; |
|||
ds_local_file_t *local_file; |
|||
ds_file_t *file; |
|||
File fd; |
|||
|
|||
fn_format(fullpath, path, ctxt->root, "", MYF(MY_RELATIVE_PATH)); |
|||
|
|||
/* Create the directory if needed */ |
|||
dirname_part(dirpath, fullpath, &dirpath_len); |
|||
if (my_mkdir(dirpath, 0777, MYF(0)) < 0 && my_errno != EEXIST) { |
|||
char errbuf[MYSYS_STRERROR_SIZE]; |
|||
my_strerror(errbuf, sizeof(errbuf), my_errno); |
|||
my_error(EE_CANT_MKDIR, MYF(ME_BELL | ME_WAITTANG), |
|||
dirpath, my_errno, errbuf); |
|||
return NULL; |
|||
} |
|||
|
|||
fd = my_create(fullpath, 0, O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW, |
|||
MYF(MY_WME)); |
|||
if (fd < 0) { |
|||
return NULL; |
|||
} |
|||
|
|||
path_len = strlen(fullpath) + 1; /* terminating '\0' */ |
|||
|
|||
file = (ds_file_t *) my_malloc(sizeof(ds_file_t) + |
|||
sizeof(ds_local_file_t) + |
|||
path_len, |
|||
MYF(MY_FAE)); |
|||
local_file = (ds_local_file_t *) (file + 1); |
|||
|
|||
local_file->fd = fd; |
|||
|
|||
file->path = (char *) local_file + sizeof(ds_local_file_t); |
|||
memcpy(file->path, fullpath, path_len); |
|||
|
|||
file->ptr = local_file; |
|||
|
|||
return file; |
|||
} |
|||
|
|||
static |
|||
int |
|||
local_write(ds_file_t *file, const void *buf, size_t len) |
|||
{ |
|||
File fd = ((ds_local_file_t *) file->ptr)->fd; |
|||
|
|||
if (!my_write(fd, buf, len, MYF(MY_WME | MY_NABP))) { |
|||
posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED); |
|||
return 0; |
|||
} |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
static |
|||
int |
|||
local_close(ds_file_t *file) |
|||
{ |
|||
File fd = ((ds_local_file_t *) file->ptr)->fd; |
|||
|
|||
my_free(file); |
|||
|
|||
my_sync(fd, MYF(MY_WME)); |
|||
|
|||
return my_close(fd, MYF(MY_WME)); |
|||
} |
|||
|
|||
static |
|||
void |
|||
local_deinit(ds_ctxt_t *ctxt) |
|||
{ |
|||
my_free(ctxt->root); |
|||
my_free(ctxt); |
|||
} |
@ -0,0 +1,28 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2011-2013 Percona LLC and/or its affiliates. |
|||
|
|||
Local datasink interface for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef DS_LOCAL_H |
|||
#define DS_LOCAL_H |
|||
|
|||
#include "datasink.h" |
|||
|
|||
extern datasink_t datasink_local; |
|||
|
|||
#endif |
@ -0,0 +1,121 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2013 Percona LLC and/or its affiliates. |
|||
|
|||
Local datasink implementation for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include <my_base.h> |
|||
#include <mysys_err.h> |
|||
#include "common.h" |
|||
#include "datasink.h" |
|||
|
|||
typedef struct { |
|||
File fd; |
|||
} ds_stdout_file_t; |
|||
|
|||
static ds_ctxt_t *stdout_init(const char *root); |
|||
static ds_file_t *stdout_open(ds_ctxt_t *ctxt, const char *path, |
|||
MY_STAT *mystat); |
|||
static int stdout_write(ds_file_t *file, const void *buf, size_t len); |
|||
static int stdout_close(ds_file_t *file); |
|||
static void stdout_deinit(ds_ctxt_t *ctxt); |
|||
|
|||
datasink_t datasink_stdout = { |
|||
&stdout_init, |
|||
&stdout_open, |
|||
&stdout_write, |
|||
&stdout_close, |
|||
&stdout_deinit |
|||
}; |
|||
|
|||
static |
|||
ds_ctxt_t * |
|||
stdout_init(const char *root) |
|||
{ |
|||
ds_ctxt_t *ctxt; |
|||
|
|||
ctxt = my_malloc(sizeof(ds_ctxt_t), MYF(MY_FAE)); |
|||
|
|||
ctxt->root = my_strdup(root, MYF(MY_FAE)); |
|||
|
|||
return ctxt; |
|||
} |
|||
|
|||
static |
|||
ds_file_t * |
|||
stdout_open(ds_ctxt_t *ctxt __attribute__((unused)), |
|||
const char *path __attribute__((unused)), |
|||
MY_STAT *mystat __attribute__((unused))) |
|||
{ |
|||
ds_stdout_file_t *stdout_file; |
|||
ds_file_t *file; |
|||
size_t pathlen; |
|||
const char *fullpath = "<STDOUT>"; |
|||
|
|||
pathlen = strlen(fullpath) + 1; |
|||
|
|||
file = (ds_file_t *) my_malloc(sizeof(ds_file_t) + |
|||
sizeof(ds_stdout_file_t) + |
|||
pathlen, |
|||
MYF(MY_FAE)); |
|||
stdout_file = (ds_stdout_file_t *) (file + 1); |
|||
|
|||
|
|||
#ifdef __WIN__ |
|||
setmode(fileno(stdout), _O_BINARY); |
|||
#endif |
|||
|
|||
stdout_file->fd = my_fileno(stdout); |
|||
|
|||
file->path = (char *) stdout_file + sizeof(ds_stdout_file_t); |
|||
memcpy(file->path, fullpath, pathlen); |
|||
|
|||
file->ptr = stdout_file; |
|||
|
|||
return file; |
|||
} |
|||
|
|||
static |
|||
int |
|||
stdout_write(ds_file_t *file, const void *buf, size_t len) |
|||
{ |
|||
File fd = ((ds_stdout_file_t *) file->ptr)->fd; |
|||
|
|||
if (!my_write(fd, buf, len, MYF(MY_WME | MY_NABP))) { |
|||
posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED); |
|||
return 0; |
|||
} |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
static |
|||
int |
|||
stdout_close(ds_file_t *file) |
|||
{ |
|||
my_free(file); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
static |
|||
void |
|||
stdout_deinit(ds_ctxt_t *ctxt) |
|||
{ |
|||
my_free(ctxt->root); |
|||
my_free(ctxt); |
|||
} |
@ -0,0 +1,28 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2013 Percona LLC and/or its affiliates. |
|||
|
|||
Local datasink interface for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef DS_STDOUT_H |
|||
#define DS_STDOUT_H |
|||
|
|||
#include "datasink.h" |
|||
|
|||
extern datasink_t datasink_stdout; |
|||
|
|||
#endif |
@ -0,0 +1,247 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2012 Percona LLC and/or its affiliates. |
|||
|
|||
tmpfile datasink for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
/* Do all writes to temporary files first, then pipe them to the specified |
|||
datasink in a serialized way in deinit(). */ |
|||
|
|||
#include <my_base.h> |
|||
#include "common.h" |
|||
#include "datasink.h" |
|||
|
|||
typedef struct { |
|||
pthread_mutex_t mutex; |
|||
LIST *file_list; |
|||
} ds_tmpfile_ctxt_t; |
|||
|
|||
typedef struct { |
|||
LIST list; |
|||
File fd; |
|||
char *orig_path; |
|||
MY_STAT mystat; |
|||
ds_file_t *file; |
|||
} ds_tmp_file_t; |
|||
|
|||
static ds_ctxt_t *tmpfile_init(const char *root); |
|||
static ds_file_t *tmpfile_open(ds_ctxt_t *ctxt, const char *path, |
|||
MY_STAT *mystat); |
|||
static int tmpfile_write(ds_file_t *file, const void *buf, size_t len); |
|||
static int tmpfile_close(ds_file_t *file); |
|||
static void tmpfile_deinit(ds_ctxt_t *ctxt); |
|||
|
|||
datasink_t datasink_tmpfile = { |
|||
&tmpfile_init, |
|||
&tmpfile_open, |
|||
&tmpfile_write, |
|||
&tmpfile_close, |
|||
&tmpfile_deinit |
|||
}; |
|||
|
|||
|
|||
static ds_ctxt_t * |
|||
tmpfile_init(const char *root) |
|||
{ |
|||
ds_ctxt_t *ctxt; |
|||
ds_tmpfile_ctxt_t *tmpfile_ctxt; |
|||
|
|||
ctxt = my_malloc(sizeof(ds_ctxt_t) + sizeof(ds_tmpfile_ctxt_t), |
|||
MYF(MY_FAE)); |
|||
tmpfile_ctxt = (ds_tmpfile_ctxt_t *) (ctxt + 1); |
|||
tmpfile_ctxt->file_list = NULL; |
|||
if (pthread_mutex_init(&tmpfile_ctxt->mutex, NULL)) { |
|||
|
|||
my_free(ctxt); |
|||
return NULL; |
|||
} |
|||
|
|||
ctxt->ptr = tmpfile_ctxt; |
|||
ctxt->root = my_strdup(root, MYF(MY_FAE)); |
|||
|
|||
return ctxt; |
|||
} |
|||
|
|||
static ds_file_t * |
|||
tmpfile_open(ds_ctxt_t *ctxt, const char *path, |
|||
MY_STAT *mystat) |
|||
{ |
|||
ds_tmpfile_ctxt_t *tmpfile_ctxt; |
|||
char tmp_path[FN_REFLEN]; |
|||
ds_tmp_file_t *tmp_file; |
|||
ds_file_t *file; |
|||
size_t path_len; |
|||
File fd; |
|||
|
|||
/* Create a temporary file in tmpdir. The file will be automatically |
|||
removed on close. Code copied from mysql_tmpfile(). */ |
|||
fd = create_temp_file(tmp_path,xtrabackup_tmpdir, |
|||
"xbtemp", |
|||
#ifdef __WIN__ |
|||
O_BINARY | O_TRUNC | O_SEQUENTIAL | |
|||
O_TEMPORARY | O_SHORT_LIVED | |
|||
#endif /* __WIN__ */ |
|||
O_CREAT | O_EXCL | O_RDWR, |
|||
MYF(MY_WME)); |
|||
|
|||
#ifndef __WIN__ |
|||
if (fd >= 0) { |
|||
/* On Windows, open files cannot be removed, but files can be |
|||
created with the O_TEMPORARY flag to the same effect |
|||
("delete on close"). */ |
|||
unlink(tmp_path); |
|||
} |
|||
#endif /* !__WIN__ */ |
|||
|
|||
if (fd < 0) { |
|||
return NULL; |
|||
} |
|||
|
|||
path_len = strlen(path) + 1; /* terminating '\0' */ |
|||
|
|||
file = (ds_file_t *) my_malloc(sizeof(ds_file_t) + |
|||
sizeof(ds_tmp_file_t) + path_len, |
|||
MYF(MY_FAE)); |
|||
|
|||
tmp_file = (ds_tmp_file_t *) (file + 1); |
|||
tmp_file->file = file; |
|||
memcpy(&tmp_file->mystat, mystat, sizeof(MY_STAT)); |
|||
/* Save a copy of 'path', since it may not be accessible later */ |
|||
tmp_file->orig_path = (char *) tmp_file + sizeof(ds_tmp_file_t); |
|||
|
|||
tmp_file->fd = fd; |
|||
memcpy(tmp_file->orig_path, path, path_len); |
|||
|
|||
/* Store the real temporary file name in file->path */ |
|||
file->path = my_strdup(tmp_path, MYF(MY_FAE)); |
|||
file->ptr = tmp_file; |
|||
|
|||
/* Store the file object in the list to be piped later */ |
|||
tmpfile_ctxt = (ds_tmpfile_ctxt_t *) ctxt->ptr; |
|||
tmp_file->list.data = tmp_file; |
|||
|
|||
pthread_mutex_lock(&tmpfile_ctxt->mutex); |
|||
tmpfile_ctxt->file_list = list_add(tmpfile_ctxt->file_list, |
|||
&tmp_file->list); |
|||
pthread_mutex_unlock(&tmpfile_ctxt->mutex); |
|||
|
|||
return file; |
|||
} |
|||
|
|||
static int |
|||
tmpfile_write(ds_file_t *file, const void *buf, size_t len) |
|||
{ |
|||
File fd = ((ds_tmp_file_t *) file->ptr)->fd; |
|||
|
|||
if (!my_write(fd, buf, len, MYF(MY_WME | MY_NABP))) { |
|||
posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED); |
|||
return 0; |
|||
} |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
static int |
|||
tmpfile_close(ds_file_t *file) |
|||
{ |
|||
/* Do nothing -- we will close (and thus remove) the file after piping |
|||
it to the destination datasink in tmpfile_deinit(). */ |
|||
|
|||
my_free(file->path); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static void |
|||
tmpfile_deinit(ds_ctxt_t *ctxt) |
|||
{ |
|||
LIST *list; |
|||
ds_tmpfile_ctxt_t *tmpfile_ctxt; |
|||
MY_STAT mystat; |
|||
ds_tmp_file_t *tmp_file; |
|||
ds_file_t *dst_file; |
|||
ds_ctxt_t *pipe_ctxt; |
|||
void *buf = NULL; |
|||
const size_t buf_size = 10 * 1024 * 1024; |
|||
size_t bytes; |
|||
size_t offset; |
|||
|
|||
pipe_ctxt = ctxt->pipe_ctxt; |
|||
xb_a(pipe_ctxt != NULL); |
|||
|
|||
buf = my_malloc(buf_size, MYF(MY_FAE)); |
|||
|
|||
tmpfile_ctxt = (ds_tmpfile_ctxt_t *) ctxt->ptr; |
|||
list = tmpfile_ctxt->file_list; |
|||
|
|||
/* Walk the files in the order they have been added */ |
|||
list = list_reverse(list); |
|||
while (list != NULL) { |
|||
tmp_file = list->data; |
|||
/* Stat the file to replace size and mtime on the original |
|||
* mystat struct */ |
|||
if (my_fstat(tmp_file->fd, &mystat, MYF(0))) { |
|||
msg("error: my_fstat() failed.\n"); |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
tmp_file->mystat.st_size = mystat.st_size; |
|||
tmp_file->mystat.st_mtime = mystat.st_mtime; |
|||
|
|||
dst_file = ds_open(pipe_ctxt, tmp_file->orig_path, |
|||
&tmp_file->mystat); |
|||
if (dst_file == NULL) { |
|||
msg("error: could not stream a temporary file to " |
|||
"'%s'\n", tmp_file->orig_path); |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
/* copy to the destination datasink */ |
|||
posix_fadvise(tmp_file->fd, 0, 0, POSIX_FADV_SEQUENTIAL); |
|||
if (my_seek(tmp_file->fd, 0, SEEK_SET, MYF(0)) == |
|||
MY_FILEPOS_ERROR) { |
|||
msg("error: my_seek() failed for '%s', errno = %d.\n", |
|||
tmp_file->file->path, my_errno); |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
offset = 0; |
|||
while ((bytes = my_read(tmp_file->fd, buf, buf_size, |
|||
MYF(MY_WME))) > 0) { |
|||
posix_fadvise(tmp_file->fd, offset, buf_size, POSIX_FADV_DONTNEED); |
|||
offset += buf_size; |
|||
if (ds_write(dst_file, buf, bytes)) { |
|||
msg("error: cannot write to stream for '%s'.\n", |
|||
tmp_file->orig_path); |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
} |
|||
if (bytes == (size_t) -1) { |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
my_close(tmp_file->fd, MYF(MY_WME)); |
|||
ds_close(dst_file); |
|||
|
|||
list = list_rest(list); |
|||
my_free(tmp_file->file); |
|||
} |
|||
|
|||
pthread_mutex_destroy(&tmpfile_ctxt->mutex); |
|||
|
|||
my_free(buf); |
|||
my_free(ctxt->root); |
|||
my_free(ctxt); |
|||
} |
@ -0,0 +1,30 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2012 Percona LLC and/or its affiliates. |
|||
|
|||
tmpfile datasink for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef DS_TMPFILE_H |
|||
#define DS_TMPFILE_H |
|||
|
|||
#include "datasink.h" |
|||
|
|||
extern datasink_t datasink_tmpfile; |
|||
|
|||
extern MY_TMPDIR mysql_tmpdir_list; |
|||
|
|||
#endif |
@ -0,0 +1,223 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2011-2013 Percona LLC and/or its affiliates. |
|||
|
|||
Streaming implementation for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include <mysql_version.h> |
|||
#include <my_base.h> |
|||
#include "common.h" |
|||
#include "datasink.h" |
|||
#include "xbstream.h" |
|||
|
|||
typedef struct { |
|||
xb_wstream_t *xbstream; |
|||
ds_file_t *dest_file; |
|||
pthread_mutex_t mutex; |
|||
} ds_stream_ctxt_t; |
|||
|
|||
typedef struct { |
|||
xb_wstream_file_t *xbstream_file; |
|||
ds_stream_ctxt_t *stream_ctxt; |
|||
} ds_stream_file_t; |
|||
|
|||
/*********************************************************************** |
|||
General streaming interface */ |
|||
|
|||
static ds_ctxt_t *xbstream_init(const char *root); |
|||
static ds_file_t *xbstream_open(ds_ctxt_t *ctxt, const char *path, |
|||
MY_STAT *mystat); |
|||
static int xbstream_write(ds_file_t *file, const void *buf, size_t len); |
|||
static int xbstream_close(ds_file_t *file); |
|||
static void xbstream_deinit(ds_ctxt_t *ctxt); |
|||
|
|||
datasink_t datasink_xbstream = { |
|||
&xbstream_init, |
|||
&xbstream_open, |
|||
&xbstream_write, |
|||
&xbstream_close, |
|||
&xbstream_deinit |
|||
}; |
|||
|
|||
static |
|||
ssize_t |
|||
my_xbstream_write_callback(xb_wstream_file_t *f __attribute__((unused)), |
|||
void *userdata, const void *buf, size_t len) |
|||
{ |
|||
ds_stream_ctxt_t *stream_ctxt; |
|||
|
|||
stream_ctxt = (ds_stream_ctxt_t *) userdata; |
|||
|
|||
xb_ad(stream_ctxt != NULL); |
|||
xb_ad(stream_ctxt->dest_file != NULL); |
|||
|
|||
if (!ds_write(stream_ctxt->dest_file, buf, len)) { |
|||
return len; |
|||
} |
|||
return -1; |
|||
} |
|||
|
|||
static |
|||
ds_ctxt_t * |
|||
xbstream_init(const char *root __attribute__((unused))) |
|||
{ |
|||
ds_ctxt_t *ctxt; |
|||
ds_stream_ctxt_t *stream_ctxt; |
|||
xb_wstream_t *xbstream; |
|||
|
|||
ctxt = my_malloc(sizeof(ds_ctxt_t) + sizeof(ds_stream_ctxt_t), |
|||
MYF(MY_FAE)); |
|||
stream_ctxt = (ds_stream_ctxt_t *)(ctxt + 1); |
|||
|
|||
if (pthread_mutex_init(&stream_ctxt->mutex, NULL)) { |
|||
msg("xbstream_init: pthread_mutex_init() failed.\n"); |
|||
goto err; |
|||
} |
|||
|
|||
xbstream = xb_stream_write_new(); |
|||
if (xbstream == NULL) { |
|||
msg("xb_stream_write_new() failed.\n"); |
|||
goto err; |
|||
} |
|||
stream_ctxt->xbstream = xbstream; |
|||
stream_ctxt->dest_file = NULL; |
|||
|
|||
ctxt->ptr = stream_ctxt; |
|||
|
|||
return ctxt; |
|||
|
|||
err: |
|||
my_free(ctxt); |
|||
return NULL; |
|||
} |
|||
|
|||
static |
|||
ds_file_t * |
|||
xbstream_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) |
|||
{ |
|||
ds_file_t *file; |
|||
ds_stream_file_t *stream_file; |
|||
ds_stream_ctxt_t *stream_ctxt; |
|||
ds_ctxt_t *dest_ctxt; |
|||
xb_wstream_t *xbstream; |
|||
xb_wstream_file_t *xbstream_file; |
|||
|
|||
|
|||
xb_ad(ctxt->pipe_ctxt != NULL); |
|||
dest_ctxt = ctxt->pipe_ctxt; |
|||
|
|||
stream_ctxt = (ds_stream_ctxt_t *) ctxt->ptr; |
|||
|
|||
pthread_mutex_lock(&stream_ctxt->mutex); |
|||
if (stream_ctxt->dest_file == NULL) { |
|||
stream_ctxt->dest_file = ds_open(dest_ctxt, path, mystat); |
|||
if (stream_ctxt->dest_file == NULL) { |
|||
return NULL; |
|||
} |
|||
} |
|||
pthread_mutex_unlock(&stream_ctxt->mutex); |
|||
|
|||
file = (ds_file_t *) my_malloc(sizeof(ds_file_t) + |
|||
sizeof(ds_stream_file_t), |
|||
MYF(MY_FAE)); |
|||
stream_file = (ds_stream_file_t *) (file + 1); |
|||
|
|||
xbstream = stream_ctxt->xbstream; |
|||
|
|||
xbstream_file = xb_stream_write_open(xbstream, path, mystat, |
|||
stream_ctxt, |
|||
my_xbstream_write_callback); |
|||
|
|||
if (xbstream_file == NULL) { |
|||
msg("xb_stream_write_open() failed.\n"); |
|||
goto err; |
|||
} |
|||
|
|||
stream_file->xbstream_file = xbstream_file; |
|||
stream_file->stream_ctxt = stream_ctxt; |
|||
file->ptr = stream_file; |
|||
file->path = stream_ctxt->dest_file->path; |
|||
|
|||
return file; |
|||
|
|||
err: |
|||
if (stream_ctxt->dest_file) { |
|||
ds_close(stream_ctxt->dest_file); |
|||
stream_ctxt->dest_file = NULL; |
|||
} |
|||
my_free(file); |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
static |
|||
int |
|||
xbstream_write(ds_file_t *file, const void *buf, size_t len) |
|||
{ |
|||
ds_stream_file_t *stream_file; |
|||
xb_wstream_file_t *xbstream_file; |
|||
|
|||
|
|||
stream_file = (ds_stream_file_t *) file->ptr; |
|||
|
|||
xbstream_file = stream_file->xbstream_file; |
|||
|
|||
if (xb_stream_write_data(xbstream_file, buf, len)) { |
|||
msg("xb_stream_write_data() failed.\n"); |
|||
return 1; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static |
|||
int |
|||
xbstream_close(ds_file_t *file) |
|||
{ |
|||
ds_stream_file_t *stream_file; |
|||
int rc = 0; |
|||
|
|||
stream_file = (ds_stream_file_t *)file->ptr; |
|||
|
|||
rc = xb_stream_write_close(stream_file->xbstream_file); |
|||
|
|||
my_free(file); |
|||
|
|||
return rc; |
|||
} |
|||
|
|||
static |
|||
void |
|||
xbstream_deinit(ds_ctxt_t *ctxt) |
|||
{ |
|||
ds_stream_ctxt_t *stream_ctxt; |
|||
|
|||
stream_ctxt = (ds_stream_ctxt_t *) ctxt->ptr; |
|||
|
|||
if (xb_stream_write_done(stream_ctxt->xbstream)) { |
|||
msg("xb_stream_done() failed.\n"); |
|||
} |
|||
|
|||
if (stream_ctxt->dest_file) { |
|||
ds_close(stream_ctxt->dest_file); |
|||
stream_ctxt->dest_file = NULL; |
|||
} |
|||
|
|||
pthread_mutex_destroy(&stream_ctxt->mutex); |
|||
|
|||
my_free(ctxt); |
|||
} |
@ -0,0 +1,28 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2011-2013 Percona LLC and/or its affiliates. |
|||
|
|||
Streaming interface for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef DS_XBSTREAM_H |
|||
#define DS_XBSTREAM_H |
|||
|
|||
#include "datasink.h" |
|||
|
|||
extern datasink_t datasink_xbstream; |
|||
|
|||
#endif |
@ -0,0 +1,157 @@ |
|||
#include <mysqld.h>
|
|||
#include <mysql.h>
|
|||
#include <xtrabackup.h>
|
|||
#include <encryption_plugin.h>
|
|||
#include <backup_copy.h>
|
|||
#include <sql_plugin.h>
|
|||
#include <sstream>
|
|||
#include <vector>
|
|||
#include <common.h>
|
|||
#include <backup_mysql.h>
|
|||
|
|||
|
|||
extern struct st_maria_plugin *mysql_optional_plugins[]; |
|||
extern struct st_maria_plugin *mysql_mandatory_plugins[]; |
|||
static void encryption_plugin_init(int argc, char **argv); |
|||
|
|||
extern char *xb_plugin_load; |
|||
extern char *xb_plugin_dir; |
|||
|
|||
const int PLUGIN_MAX_ARGS = 1024; |
|||
vector<string> backup_plugins_args; |
|||
|
|||
const char *QUERY_PLUGIN = |
|||
"SELECT plugin_name, plugin_library, @@plugin_dir" |
|||
" FROM information_schema.plugins WHERE plugin_type='ENCRYPTION'" |
|||
" AND plugin_status='ACTIVE'"; |
|||
|
|||
string encryption_plugin_config; |
|||
|
|||
static void add_to_plugin_load_list(const char *plugin_def) |
|||
{ |
|||
opt_plugin_load_list_ptr->push_back(new i_string(plugin_def)); |
|||
} |
|||
|
|||
static char XTRABACKUP_EXE[] = "xtrabackup"; |
|||
|
|||
void encryption_plugin_backup_init(MYSQL *mysql) |
|||
{ |
|||
MYSQL_RES *result; |
|||
MYSQL_ROW row; |
|||
ostringstream oss; |
|||
char *argv[PLUGIN_MAX_ARGS]; |
|||
int argc; |
|||
|
|||
result = xb_mysql_query(mysql, QUERY_PLUGIN, true, true); |
|||
row = mysql_fetch_row(result); |
|||
if (!row) |
|||
{ |
|||
mysql_free_result(result); |
|||
return; |
|||
} |
|||
|
|||
char *name= row[0]; |
|||
char *library= row[1]; |
|||
char *dir= row[2]; |
|||
|
|||
#ifdef _WIN32
|
|||
for (char *p = dir; *p; p++) |
|||
if (*p == '\\') *p = '/'; |
|||
#endif
|
|||
|
|||
string plugin_load(name); |
|||
if (library) |
|||
plugin_load += string("=") + library; |
|||
|
|||
oss << "plugin_load=" << plugin_load << endl; |
|||
|
|||
/* Required to load the plugin later.*/ |
|||
add_to_plugin_load_list(plugin_load.c_str()); |
|||
strncpy(opt_plugin_dir, dir, FN_REFLEN); |
|||
|
|||
oss << "plugin_dir=" << '"' << dir << '"' << endl; |
|||
|
|||
|
|||
/* Read plugin variables. */ |
|||
char query[1024]; |
|||
snprintf(query, 1024, "SHOW variables like '%s_%%'", name); |
|||
mysql_free_result(result); |
|||
|
|||
result = xb_mysql_query(mysql, query, true, true); |
|||
while ((row = mysql_fetch_row(result))) |
|||
{ |
|||
string arg("--"); |
|||
arg += row[0]; |
|||
arg += "="; |
|||
arg += row[1]; |
|||
backup_plugins_args.push_back(arg); |
|||
oss << row[0] << "=" << row[1] << endl; |
|||
} |
|||
|
|||
mysql_free_result(result); |
|||
|
|||
/* Check whether to encrypt logs. */ |
|||
result = xb_mysql_query(mysql, "select @@innodb_encrypt_log", true, true); |
|||
row = mysql_fetch_row(result); |
|||
srv_encrypt_log = (row != 0 && row[0][0] == '1'); |
|||
oss << "innodb_encrypt_log=" << row[0] << endl; |
|||
|
|||
mysql_free_result(result); |
|||
|
|||
encryption_plugin_config = oss.str(); |
|||
|
|||
argc = 0; |
|||
argv[argc++] = XTRABACKUP_EXE; |
|||
for(size_t i = 0; i < backup_plugins_args.size(); i++) |
|||
{ |
|||
argv[argc++] = (char *)backup_plugins_args[i].c_str(); |
|||
if (argc == PLUGIN_MAX_ARGS - 2) |
|||
break; |
|||
} |
|||
argv[argc] = 0; |
|||
|
|||
encryption_plugin_init(argc, argv); |
|||
} |
|||
|
|||
const char *encryption_plugin_get_config() |
|||
{ |
|||
return encryption_plugin_config.c_str(); |
|||
} |
|||
|
|||
extern int finalize_encryption_plugin(st_plugin_int *plugin); |
|||
|
|||
|
|||
void encryption_plugin_prepare_init(int argc, char **argv) |
|||
{ |
|||
|
|||
if (!xb_plugin_load) |
|||
{ |
|||
/* This prevents crashes e.g in --stats with wrong my.cnf*/ |
|||
finalize_encryption_plugin(0); |
|||
return; |
|||
} |
|||
|
|||
add_to_plugin_load_list(xb_plugin_load); |
|||
|
|||
if (xb_plugin_dir) |
|||
strncpy(opt_plugin_dir, xb_plugin_dir, FN_REFLEN); |
|||
|
|||
char **new_argv = new char *[argc + 1]; |
|||
new_argv[0] = XTRABACKUP_EXE; |
|||
memcpy(&new_argv[1], argv, argc*sizeof(char *)); |
|||
|
|||
encryption_plugin_init(argc+1, new_argv); |
|||
|
|||
delete[] new_argv; |
|||
} |
|||
|
|||
static void encryption_plugin_init(int argc, char **argv) |
|||
{ |
|||
/* Patch optional and mandatory plugins, we only need to load the one in xb_plugin_load. */ |
|||
mysql_optional_plugins[0] = mysql_mandatory_plugins[0] = 0; |
|||
msg("Loading encryption plugin\n"); |
|||
for (int i= 1; i < argc; i++) |
|||
msg("\t Encryption plugin parameter : '%s'\n", argv[i]); |
|||
plugin_init(&argc, argv, PLUGIN_INIT_SKIP_PLUGIN_TABLE); |
|||
} |
|||
|
@ -0,0 +1,7 @@ |
|||
#include <mysql.h> |
|||
#include <string> |
|||
extern void encryption_plugin_backup_init(MYSQL *mysql); |
|||
extern const char* encryption_plugin_get_config(); |
|||
extern void encryption_plugin_prepare_init(int argc, char **argv); |
|||
|
|||
//extern void encryption_plugin_init(int argc, char **argv); |
@ -0,0 +1,409 @@ |
|||
/******************************************************
|
|||
XtraBackup: hot backup tool for InnoDB |
|||
(c) 2009-2013 Percona LLC and/or its affiliates. |
|||
Originally Created 3/3/2009 Yasufumi Kinoshita |
|||
Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko, |
|||
Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
/* Source file cursor implementation */ |
|||
|
|||
#include <my_base.h>
|
|||
|
|||
#include <univ.i>
|
|||
#include <fil0fil.h>
|
|||
#include <srv0start.h>
|
|||
#include <trx0sys.h>
|
|||
|
|||
#include "fil_cur.h"
|
|||
#include "common.h"
|
|||
#include "read_filt.h"
|
|||
#include "xtrabackup.h"
|
|||
#include "xb0xb.h"
|
|||
|
|||
/* Size of read buffer in pages (640 pages = 10M for 16K sized pages) */ |
|||
#define XB_FIL_CUR_PAGES 640
|
|||
|
|||
/***********************************************************************
|
|||
Extracts the relative path ("database/table.ibd") of a tablespace from a |
|||
specified possibly absolute path. |
|||
|
|||
For user tablespaces both "./database/table.ibd" and |
|||
"/remote/dir/database/table.ibd" result in "database/table.ibd". |
|||
|
|||
For system tablepsaces (i.e. When is_system is TRUE) both "/remote/dir/ibdata1" |
|||
and "./ibdata1" yield "ibdata1" in the output. */ |
|||
const char * |
|||
xb_get_relative_path( |
|||
/*=================*/ |
|||
const char* path, /*!< in: tablespace path (either
|
|||
relative or absolute) */ |
|||
ibool is_system) /*!< in: TRUE for system tablespaces,
|
|||
i.e. when only the filename must be |
|||
returned. */ |
|||
{ |
|||
const char *next; |
|||
const char *cur; |
|||
const char *prev; |
|||
|
|||
prev = NULL; |
|||
cur = path; |
|||
|
|||
while ((next = strchr(cur, SRV_PATH_SEPARATOR)) != NULL) { |
|||
|
|||
prev = cur; |
|||
cur = next + 1; |
|||
} |
|||
|
|||
if (is_system) { |
|||
|
|||
return(cur); |
|||
} else { |
|||
|
|||
return((prev == NULL) ? cur : prev); |
|||
} |
|||
|
|||
} |
|||
|
|||
/**********************************************************************//**
|
|||
Closes a file. */ |
|||
static |
|||
void |
|||
xb_fil_node_close_file( |
|||
/*===================*/ |
|||
fil_node_t* node) /*!< in: file node */ |
|||
{ |
|||
ibool ret; |
|||
|
|||
mutex_enter(&fil_system->mutex); |
|||
|
|||
ut_ad(node); |
|||
ut_a(node->n_pending == 0); |
|||
ut_a(node->n_pending_flushes == 0); |
|||
ut_a(!node->being_extended); |
|||
|
|||
if (!node->open) { |
|||
|
|||
mutex_exit(&fil_system->mutex); |
|||
|
|||
return; |
|||
} |
|||
|
|||
ret = os_file_close(node->handle); |
|||
ut_a(ret); |
|||
|
|||
node->open = FALSE; |
|||
|
|||
ut_a(fil_system->n_open > 0); |
|||
fil_system->n_open--; |
|||
fil_n_file_opened--; |
|||
|
|||
if (node->space->purpose == FIL_TABLESPACE && |
|||
fil_is_user_tablespace_id(node->space->id)) { |
|||
|
|||
ut_a(UT_LIST_GET_LEN(fil_system->LRU) > 0); |
|||
|
|||
/* The node is in the LRU list, remove it */ |
|||
UT_LIST_REMOVE(LRU, fil_system->LRU, node); |
|||
} |
|||
|
|||
mutex_exit(&fil_system->mutex); |
|||
} |
|||
|
|||
/************************************************************************
|
|||
Open a source file cursor and initialize the associated read filter. |
|||
|
|||
@return XB_FIL_CUR_SUCCESS on success, XB_FIL_CUR_SKIP if the source file must |
|||
be skipped and XB_FIL_CUR_ERROR on error. */ |
|||
xb_fil_cur_result_t |
|||
xb_fil_cur_open( |
|||
/*============*/ |
|||
xb_fil_cur_t* cursor, /*!< out: source file cursor */ |
|||
xb_read_filt_t* read_filter, /*!< in/out: the read filter */ |
|||
fil_node_t* node, /*!< in: source tablespace node */ |
|||
uint thread_n) /*!< thread number for diagnostics */ |
|||
{ |
|||
ulint page_size; |
|||
ulint page_size_shift; |
|||
ulint zip_size; |
|||
ibool success; |
|||
|
|||
/* Initialize these first so xb_fil_cur_close() handles them correctly
|
|||
in case of error */ |
|||
cursor->orig_buf = NULL; |
|||
cursor->node = NULL; |
|||
|
|||
cursor->space_id = node->space->id; |
|||
cursor->is_system = !fil_is_user_tablespace_id(node->space->id); |
|||
|
|||
strncpy(cursor->abs_path, node->name, sizeof(cursor->abs_path)); |
|||
|
|||
/* Get the relative path for the destination tablespace name, i.e. the
|
|||
one that can be appended to the backup root directory. Non-system |
|||
tablespaces may have absolute paths for remote tablespaces in MySQL |
|||
5.6+. We want to make "local" copies for the backup. */ |
|||
strncpy(cursor->rel_path, |
|||
xb_get_relative_path(cursor->abs_path, cursor->is_system), |
|||
sizeof(cursor->rel_path)); |
|||
|
|||
/* In the backup mode we should already have a tablespace handle created
|
|||
by fil_load_single_table_tablespace() unless it is a system |
|||
tablespace. Otherwise we open the file here. */ |
|||
if (cursor->is_system || !srv_backup_mode || srv_close_files) { |
|||
node->handle = |
|||
os_file_create_simple_no_error_handling(0, node->name, |
|||
OS_FILE_OPEN, |
|||
OS_FILE_READ_ONLY, |
|||
&success,0); |
|||
if (!success) { |
|||
/* The following call prints an error message */ |
|||
os_file_get_last_error(TRUE); |
|||
|
|||
msg("[%02u] xtrabackup: error: cannot open " |
|||
"tablespace %s\n", |
|||
thread_n, cursor->abs_path); |
|||
|
|||
return(XB_FIL_CUR_ERROR); |
|||
} |
|||
mutex_enter(&fil_system->mutex); |
|||
|
|||
node->open = TRUE; |
|||
|
|||
fil_system->n_open++; |
|||
fil_n_file_opened++; |
|||
|
|||
if (node->space->purpose == FIL_TABLESPACE && |
|||
fil_is_user_tablespace_id(node->space->id)) { |
|||
|
|||
/* Put the node to the LRU list */ |
|||
UT_LIST_ADD_FIRST(LRU, fil_system->LRU, node); |
|||
} |
|||
|
|||
mutex_exit(&fil_system->mutex); |
|||
} |
|||
|
|||
ut_ad(node->open); |
|||
|
|||
cursor->node = node; |
|||
cursor->file = node->handle; |
|||
|
|||
if (stat(cursor->abs_path, &cursor->statinfo)) { |
|||
msg("[%02u] xtrabackup: error: cannot stat %s\n", |
|||
thread_n, cursor->abs_path); |
|||
|
|||
xb_fil_cur_close(cursor); |
|||
|
|||
return(XB_FIL_CUR_ERROR); |
|||
} |
|||
|
|||
if (srv_unix_file_flush_method == SRV_UNIX_O_DIRECT |
|||
|| srv_unix_file_flush_method == SRV_UNIX_O_DIRECT_NO_FSYNC) { |
|||
|
|||
os_file_set_nocache(cursor->file, node->name, "OPEN"); |
|||
} |
|||
|
|||
posix_fadvise(cursor->file, 0, 0, POSIX_FADV_SEQUENTIAL); |
|||
|
|||
/* Determine the page size */ |
|||
zip_size = xb_get_zip_size(cursor->file); |
|||
if (zip_size == ULINT_UNDEFINED) { |
|||
xb_fil_cur_close(cursor); |
|||
return(XB_FIL_CUR_SKIP); |
|||
} else if (zip_size) { |
|||
page_size = zip_size; |
|||
page_size_shift = get_bit_shift(page_size); |
|||
msg("[%02u] %s is compressed with page size = " |
|||
"%lu bytes\n", thread_n, node->name, page_size); |
|||
if (page_size_shift < 10 || page_size_shift > 14) { |
|||
msg("[%02u] xtrabackup: Error: Invalid " |
|||
"page size: %lu.\n", thread_n, page_size); |
|||
ut_error; |
|||
} |
|||
} else { |
|||
page_size = UNIV_PAGE_SIZE; |
|||
page_size_shift = UNIV_PAGE_SIZE_SHIFT; |
|||
} |
|||
cursor->page_size = page_size; |
|||
cursor->page_size_shift = page_size_shift; |
|||
cursor->zip_size = zip_size; |
|||
|
|||
/* Allocate read buffer */ |
|||
cursor->buf_size = XB_FIL_CUR_PAGES * page_size; |
|||
cursor->orig_buf = static_cast<byte *> |
|||
(ut_malloc(cursor->buf_size + UNIV_PAGE_SIZE)); |
|||
cursor->buf = static_cast<byte *> |
|||
(ut_align(cursor->orig_buf, UNIV_PAGE_SIZE)); |
|||
|
|||
cursor->buf_read = 0; |
|||
cursor->buf_npages = 0; |
|||
cursor->buf_offset = 0; |
|||
cursor->buf_page_no = 0; |
|||
cursor->thread_n = thread_n; |
|||
|
|||
cursor->space_size = (ulint)(cursor->statinfo.st_size / page_size); |
|||
|
|||
cursor->read_filter = read_filter; |
|||
cursor->read_filter->init(&cursor->read_filter_ctxt, cursor, |
|||
node->space->id); |
|||
|
|||
return(XB_FIL_CUR_SUCCESS); |
|||
} |
|||
|
|||
/************************************************************************
|
|||
Reads and verifies the next block of pages from the source |
|||
file. Positions the cursor after the last read non-corrupted page. |
|||
|
|||
@return XB_FIL_CUR_SUCCESS if some have been read successfully, XB_FIL_CUR_EOF |
|||
if there are no more pages to read and XB_FIL_CUR_ERROR on error. */ |
|||
xb_fil_cur_result_t |
|||
xb_fil_cur_read( |
|||
/*============*/ |
|||
xb_fil_cur_t* cursor) /*!< in/out: source file cursor */ |
|||
{ |
|||
ibool success; |
|||
byte* page; |
|||
ulint i; |
|||
ulint npages; |
|||
ulint retry_count; |
|||
xb_fil_cur_result_t ret; |
|||
ib_int64_t offset; |
|||
ib_int64_t to_read; |
|||
|
|||
cursor->read_filter->get_next_batch(&cursor->read_filter_ctxt, |
|||
&offset, &to_read); |
|||
|
|||
if (to_read == 0LL) { |
|||
return(XB_FIL_CUR_EOF); |
|||
} |
|||
|
|||
if (to_read > (ib_int64_t) cursor->buf_size) { |
|||
to_read = (ib_int64_t) cursor->buf_size; |
|||
} |
|||
|
|||
xb_a(to_read > 0 && to_read <= 0xFFFFFFFFLL); |
|||
|
|||
if (to_read % cursor->page_size != 0 && |
|||
offset + to_read == cursor->statinfo.st_size) { |
|||
|
|||
if (to_read < (ib_int64_t) cursor->page_size) { |
|||
msg("[%02u] xtrabackup: Warning: junk at the end of " |
|||
"%s:\n", cursor->thread_n, cursor->abs_path); |
|||
msg("[%02u] xtrabackup: Warning: offset = %llu, " |
|||
"to_read = %llu\n", |
|||
cursor->thread_n, |
|||
(unsigned long long) offset, |
|||
(unsigned long long) to_read); |
|||
|
|||
return(XB_FIL_CUR_EOF); |
|||
} |
|||
|
|||
to_read = (ib_int64_t) (((ulint) to_read) & |
|||
~(cursor->page_size - 1)); |
|||
} |
|||
|
|||
xb_a(to_read % cursor->page_size == 0); |
|||
|
|||
npages = (ulint) (to_read >> cursor->page_size_shift); |
|||
|
|||
retry_count = 10; |
|||
ret = XB_FIL_CUR_SUCCESS; |
|||
|
|||
read_retry: |
|||
xtrabackup_io_throttling(); |
|||
|
|||
cursor->buf_read = 0; |
|||
cursor->buf_npages = 0; |
|||
cursor->buf_offset = offset; |
|||
cursor->buf_page_no = (ulint)(offset >> cursor->page_size_shift); |
|||
|
|||
success = os_file_read(cursor->file, cursor->buf, offset, |
|||
(ulint)to_read); |
|||
if (!success) { |
|||
return(XB_FIL_CUR_ERROR); |
|||
} |
|||
|
|||
fil_system_enter(); |
|||
fil_space_t *space = fil_space_get_by_id(cursor->space_id); |
|||
fil_system_exit(); |
|||
|
|||
/* check pages for corruption and re-read if necessary. i.e. in case of
|
|||
partially written pages */ |
|||
for (page = cursor->buf, i = 0; i < npages; |
|||
page += cursor->page_size, i++) { |
|||
ib_int64_t page_no = cursor->buf_page_no + i; |
|||
|
|||
bool checksum_ok = fil_space_verify_crypt_checksum(page, cursor->zip_size,space, (ulint)page_no); |
|||
|
|||
if (!checksum_ok && |
|||
buf_page_is_corrupted(true, page, cursor->zip_size,space)) { |
|||
|
|||
if (cursor->is_system && |
|||
page_no >= (ib_int64_t)FSP_EXTENT_SIZE && |
|||
page_no < (ib_int64_t) FSP_EXTENT_SIZE * 3) { |
|||
/* skip doublewrite buffer pages */ |
|||
xb_a(cursor->page_size == UNIV_PAGE_SIZE); |
|||
msg("[%02u] xtrabackup: " |
|||
"Page %lu is a doublewrite buffer page, " |
|||
"skipping.\n", cursor->thread_n, page_no); |
|||
} else { |
|||
retry_count--; |
|||
if (retry_count == 0) { |
|||
msg("[%02u] xtrabackup: " |
|||
"Error: failed to read page after " |
|||
"10 retries. File %s seems to be " |
|||
"corrupted.\n", cursor->thread_n, |
|||
cursor->abs_path); |
|||
ret = XB_FIL_CUR_ERROR; |
|||
break; |
|||
} |
|||
msg("[%02u] xtrabackup: " |
|||
"Database page corruption detected at page " |
|||
"%lu, retrying...\n", cursor->thread_n, |
|||
page_no); |
|||
|
|||
os_thread_sleep(100000); |
|||
|
|||
goto read_retry; |
|||
} |
|||
} |
|||
cursor->buf_read += cursor->page_size; |
|||
cursor->buf_npages++; |
|||
} |
|||
|
|||
posix_fadvise(cursor->file, offset, to_read, POSIX_FADV_DONTNEED); |
|||
|
|||
return(ret); |
|||
} |
|||
|
|||
/************************************************************************
|
|||
Close the source file cursor opened with xb_fil_cur_open() and its |
|||
associated read filter. */ |
|||
void |
|||
xb_fil_cur_close( |
|||
/*=============*/ |
|||
xb_fil_cur_t *cursor) /*!< in/out: source file cursor */ |
|||
{ |
|||
cursor->read_filter->deinit(&cursor->read_filter_ctxt); |
|||
|
|||
if (cursor->orig_buf != NULL) { |
|||
ut_free(cursor->orig_buf); |
|||
} |
|||
if (cursor->node != NULL) { |
|||
xb_fil_node_close_file(cursor->node); |
|||
cursor->file = XB_FILE_UNDEFINED; |
|||
} |
|||
} |
@ -0,0 +1,123 @@ |
|||
/****************************************************** |
|||
XtraBackup: hot backup tool for InnoDB |
|||
(c) 2009-2013 Percona LLC and/or its affiliates. |
|||
Originally Created 3/3/2009 Yasufumi Kinoshita |
|||
Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko, |
|||
Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
/* Source file cursor interface */ |
|||
|
|||
#ifndef FIL_CUR_H |
|||
#define FIL_CUR_H |
|||
|
|||
#include <my_dir.h> |
|||
#include "read_filt.h" |
|||
|
|||
struct xb_fil_cur_t { |
|||
os_file_t file; /*!< source file handle */ |
|||
fil_node_t* node; /*!< source tablespace node */ |
|||
char rel_path[FN_REFLEN]; |
|||
/*!< normalized file path */ |
|||
char abs_path[FN_REFLEN]; |
|||
/*!< absolute file path */ |
|||
MY_STAT statinfo; /*!< information about the file */ |
|||
ulint zip_size; /*!< compressed page size in bytes or 0 |
|||
for uncompressed pages */ |
|||
ulint page_size; /*!< = zip_size for compressed pages or |
|||
UNIV_PAGE_SIZE for uncompressed ones */ |
|||
ulint page_size_shift;/*!< bit shift corresponding to |
|||
page_size */ |
|||
my_bool is_system; /*!< TRUE for system tablespace, FALSE |
|||
otherwise */ |
|||
xb_read_filt_t* read_filter; /*!< read filter */ |
|||
xb_read_filt_ctxt_t read_filter_ctxt; |
|||
/*!< read filter context */ |
|||
byte* orig_buf; /*!< read buffer */ |
|||
byte* buf; /*!< aligned pointer for orig_buf */ |
|||
size_t buf_size; /*!< buffer size in bytes */ |
|||
size_t buf_read; /*!< number of read bytes in buffer |
|||
after the last cursor read */ |
|||
size_t buf_npages; /*!< number of pages in buffer after the |
|||
last cursor read */ |
|||
ib_int64_t buf_offset; /*!< file offset of the first page in |
|||
buffer */ |
|||
ulint buf_page_no; /*!< number of the first page in |
|||
buffer */ |
|||
uint thread_n; /*!< thread number for diagnostics */ |
|||
ulint space_id; /*!< ID of tablespace */ |
|||
ulint space_size; /*!< space size in pages */ |
|||
}; |
|||
|
|||
typedef enum { |
|||
XB_FIL_CUR_SUCCESS, |
|||
XB_FIL_CUR_SKIP, |
|||
XB_FIL_CUR_ERROR, |
|||
XB_FIL_CUR_EOF |
|||
} xb_fil_cur_result_t; |
|||
|
|||
/************************************************************************ |
|||
Open a source file cursor and initialize the associated read filter. |
|||
|
|||
@return XB_FIL_CUR_SUCCESS on success, XB_FIL_CUR_SKIP if the source file must |
|||
be skipped and XB_FIL_CUR_ERROR on error. */ |
|||
xb_fil_cur_result_t |
|||
xb_fil_cur_open( |
|||
/*============*/ |
|||
xb_fil_cur_t* cursor, /*!< out: source file cursor */ |
|||
xb_read_filt_t* read_filter, /*!< in/out: the read filter */ |
|||
fil_node_t* node, /*!< in: source tablespace node */ |
|||
uint thread_n); /*!< thread number for diagnostics */ |
|||
|
|||
/************************************************************************ |
|||
Reads and verifies the next block of pages from the source |
|||
file. Positions the cursor after the last read non-corrupted page. |
|||
|
|||
@return XB_FIL_CUR_SUCCESS if some have been read successfully, XB_FIL_CUR_EOF |
|||
if there are no more pages to read and XB_FIL_CUR_ERROR on error. */ |
|||
xb_fil_cur_result_t |
|||
xb_fil_cur_read( |
|||
/*============*/ |
|||
xb_fil_cur_t* cursor); /*!< in/out: source file cursor */ |
|||
|
|||
/************************************************************************ |
|||
Close the source file cursor opened with xb_fil_cur_open() and its |
|||
associated read filter. */ |
|||
void |
|||
xb_fil_cur_close( |
|||
/*=============*/ |
|||
xb_fil_cur_t *cursor); /*!< in/out: source file cursor */ |
|||
|
|||
/*********************************************************************** |
|||
Extracts the relative path ("database/table.ibd") of a tablespace from a |
|||
specified possibly absolute path. |
|||
|
|||
For user tablespaces both "./database/table.ibd" and |
|||
"/remote/dir/database/table.ibd" result in "database/table.ibd". |
|||
|
|||
For system tablepsaces (i.e. When is_system is TRUE) both "/remote/dir/ibdata1" |
|||
and "./ibdata1" yield "ibdata1" in the output. */ |
|||
const char * |
|||
xb_get_relative_path( |
|||
/*=================*/ |
|||
const char* path, /*!< in: tablespace path (either |
|||
relative or absolute) */ |
|||
ibool is_system); /*!< in: TRUE for system tablespaces, |
|||
i.e. when only the filename must be |
|||
returned. */ |
|||
|
|||
#endif |
1132
extra/mariabackup/innobackupex.cc
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,45 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2011-2014 Percona LLC and/or its affiliates. |
|||
|
|||
Declarations for innobackupex.cc |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef INNOBACKUPEX_H |
|||
#define INNOBACKUPEX_H |
|||
|
|||
#define INNOBACKUPEX_BIN_NAME "innobackupex" |
|||
|
|||
enum ibx_mode_t { |
|||
IBX_MODE_BACKUP, |
|||
IBX_MODE_APPLY_LOG, |
|||
IBX_MODE_COPY_BACK, |
|||
IBX_MODE_MOVE_BACK, |
|||
IBX_MODE_DECRYPT_DECOMPRESS |
|||
}; |
|||
|
|||
extern ibx_mode_t ibx_mode; |
|||
|
|||
bool |
|||
ibx_handle_options(int *argc, char ***argv); |
|||
|
|||
bool |
|||
ibx_init(); |
|||
|
|||
void |
|||
ibx_cleanup(); |
|||
|
|||
#endif |
@ -0,0 +1,848 @@ |
|||
// Fast data compression library |
|||
// Copyright (C) 2006-2011 Lasse Mikkel Reinhold |
|||
// lar@quicklz.com |
|||
// |
|||
// QuickLZ can be used for free under the GPL 1, 2 or 3 license (where anything |
|||
// released into public must be open source) or under a commercial license if such |
|||
// has been acquired (see http://www.quicklz.com/order.html). The commercial license |
|||
// does not cover derived or ported versions created by third parties under GPL. |
|||
|
|||
// 1.5.0 final |
|||
|
|||
#include "quicklz.h" |
|||
|
|||
#if QLZ_VERSION_MAJOR != 1 || QLZ_VERSION_MINOR != 5 || QLZ_VERSION_REVISION != 0 |
|||
#error quicklz.c and quicklz.h have different versions |
|||
#endif |
|||
|
|||
#if (defined(__X86__) || defined(__i386__) || defined(i386) || defined(_M_IX86) || defined(__386__) || defined(__x86_64__) || defined(_M_X64)) |
|||
#define X86X64 |
|||
#endif |
|||
|
|||
#define MINOFFSET 2 |
|||
#define UNCONDITIONAL_MATCHLEN 6 |
|||
#define UNCOMPRESSED_END 4 |
|||
#define CWORD_LEN 4 |
|||
|
|||
#if QLZ_COMPRESSION_LEVEL == 1 && defined QLZ_PTR_64 && QLZ_STREAMING_BUFFER == 0 |
|||
#define OFFSET_BASE source |
|||
#define CAST (ui32)(size_t) |
|||
#else |
|||
#define OFFSET_BASE 0 |
|||
#define CAST |
|||
#endif |
|||
|
|||
int qlz_get_setting(int setting) |
|||
{ |
|||
switch (setting) |
|||
{ |
|||
case 0: return QLZ_COMPRESSION_LEVEL; |
|||
case 1: return sizeof(qlz_state_compress); |
|||
case 2: return sizeof(qlz_state_decompress); |
|||
case 3: return QLZ_STREAMING_BUFFER; |
|||
#ifdef QLZ_MEMORY_SAFE |
|||
case 6: return 1; |
|||
#else |
|||
case 6: return 0; |
|||
#endif |
|||
case 7: return QLZ_VERSION_MAJOR; |
|||
case 8: return QLZ_VERSION_MINOR; |
|||
case 9: return QLZ_VERSION_REVISION; |
|||
} |
|||
return -1; |
|||
} |
|||
|
|||
#if QLZ_COMPRESSION_LEVEL == 1 |
|||
static int same(const unsigned char *src, size_t n) |
|||
{ |
|||
while(n > 0 && *(src + n) == *src) |
|||
n--; |
|||
return n == 0 ? 1 : 0; |
|||
} |
|||
#endif |
|||
|
|||
static void reset_table_compress(qlz_state_compress *state) |
|||
{ |
|||
int i; |
|||
for(i = 0; i < QLZ_HASH_VALUES; i++) |
|||
{ |
|||
#if QLZ_COMPRESSION_LEVEL == 1 |
|||
state->hash[i].offset = 0; |
|||
#else |
|||
state->hash_counter[i] = 0; |
|||
#endif |
|||
} |
|||
} |
|||
|
|||
static void reset_table_decompress(qlz_state_decompress *state) |
|||
{ |
|||
int i; |
|||
(void)state; |
|||
(void)i; |
|||
#if QLZ_COMPRESSION_LEVEL == 2 |
|||
for(i = 0; i < QLZ_HASH_VALUES; i++) |
|||
{ |
|||
state->hash_counter[i] = 0; |
|||
} |
|||
#endif |
|||
} |
|||
|
|||
static __inline ui32 hash_func(ui32 i) |
|||
{ |
|||
#if QLZ_COMPRESSION_LEVEL == 2 |
|||
return ((i >> 9) ^ (i >> 13) ^ i) & (QLZ_HASH_VALUES - 1); |
|||
#else |
|||
return ((i >> 12) ^ i) & (QLZ_HASH_VALUES - 1); |
|||
#endif |
|||
} |
|||
|
|||
static __inline ui32 fast_read(void const *src, ui32 bytes) |
|||
{ |
|||
#ifndef X86X64 |
|||
unsigned char *p = (unsigned char*)src; |
|||
switch (bytes) |
|||
{ |
|||
case 4: |
|||
return(*p | *(p + 1) << 8 | *(p + 2) << 16 | *(p + 3) << 24); |
|||
case 3: |
|||
return(*p | *(p + 1) << 8 | *(p + 2) << 16); |
|||
case 2: |
|||
return(*p | *(p + 1) << 8); |
|||
case 1: |
|||
return(*p); |
|||
} |
|||
return 0; |
|||
#else |
|||
if (bytes >= 1 && bytes <= 4) |
|||
return *((ui32*)src); |
|||
else |
|||
return 0; |
|||
#endif |
|||
} |
|||
|
|||
static __inline ui32 hashat(const unsigned char *src) |
|||
{ |
|||
ui32 fetch, hash; |
|||
fetch = fast_read(src, 3); |
|||
hash = hash_func(fetch); |
|||
return hash; |
|||
} |
|||
|
|||
static __inline void fast_write(ui32 f, void *dst, size_t bytes) |
|||
{ |
|||
#ifndef X86X64 |
|||
unsigned char *p = (unsigned char*)dst; |
|||
|
|||
switch (bytes) |
|||
{ |
|||
case 4: |
|||
*p = (unsigned char)f; |
|||
*(p + 1) = (unsigned char)(f >> 8); |
|||
*(p + 2) = (unsigned char)(f >> 16); |
|||
*(p + 3) = (unsigned char)(f >> 24); |
|||
return; |
|||
case 3: |
|||
*p = (unsigned char)f; |
|||
*(p + 1) = (unsigned char)(f >> 8); |
|||
*(p + 2) = (unsigned char)(f >> 16); |
|||
return; |
|||
case 2: |
|||
*p = (unsigned char)f; |
|||
*(p + 1) = (unsigned char)(f >> 8); |
|||
return; |
|||
case 1: |
|||
*p = (unsigned char)f; |
|||
return; |
|||
} |
|||
#else |
|||
switch (bytes) |
|||
{ |
|||
case 4: |
|||
*((ui32*)dst) = f; |
|||
return; |
|||
case 3: |
|||
*((ui32*)dst) = f; |
|||
return; |
|||
case 2: |
|||
*((ui16 *)dst) = (ui16)f; |
|||
return; |
|||
case 1: |
|||
*((unsigned char*)dst) = (unsigned char)f; |
|||
return; |
|||
} |
|||
#endif |
|||
} |
|||
|
|||
|
|||
size_t qlz_size_decompressed(const char *source) |
|||
{ |
|||
ui32 n, r; |
|||
n = (((*source) & 2) == 2) ? 4 : 1; |
|||
r = fast_read(source + 1 + n, n); |
|||
r = r & (0xffffffff >> ((4 - n)*8)); |
|||
return r; |
|||
} |
|||
|
|||
size_t qlz_size_compressed(const char *source) |
|||
{ |
|||
ui32 n, r; |
|||
n = (((*source) & 2) == 2) ? 4 : 1; |
|||
r = fast_read(source + 1, n); |
|||
r = r & (0xffffffff >> ((4 - n)*8)); |
|||
return r; |
|||
} |
|||
|
|||
size_t qlz_size_header(const char *source) |
|||
{ |
|||
size_t n = 2*((((*source) & 2) == 2) ? 4 : 1) + 1; |
|||
return n; |
|||
} |
|||
|
|||
|
|||
static __inline void memcpy_up(unsigned char *dst, const unsigned char *src, ui32 n) |
|||
{ |
|||
// Caution if modifying memcpy_up! Overlap of dst and src must be special handled. |
|||
#ifndef X86X64 |
|||
unsigned char *end = dst + n; |
|||
while(dst < end) |
|||
{ |
|||
*dst = *src; |
|||
dst++; |
|||
src++; |
|||
} |
|||
#else |
|||
ui32 f = 0; |
|||
do |
|||
{ |
|||
*(ui32 *)(dst + f) = *(ui32 *)(src + f); |
|||
f += MINOFFSET + 1; |
|||
} |
|||
while (f < n); |
|||
#endif |
|||
} |
|||
|
|||
static __inline void update_hash(qlz_state_decompress *state, const unsigned char *s) |
|||
{ |
|||
#if QLZ_COMPRESSION_LEVEL == 1 |
|||
ui32 hash; |
|||
hash = hashat(s); |
|||
state->hash[hash].offset = s; |
|||
state->hash_counter[hash] = 1; |
|||
#elif QLZ_COMPRESSION_LEVEL == 2 |
|||
ui32 hash; |
|||
unsigned char c; |
|||
hash = hashat(s); |
|||
c = state->hash_counter[hash]; |
|||
state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = s; |
|||
c++; |
|||
state->hash_counter[hash] = c; |
|||
#endif |
|||
(void)state; |
|||
(void)s; |
|||
} |
|||
|
|||
#if QLZ_COMPRESSION_LEVEL <= 2 |
|||
static void update_hash_upto(qlz_state_decompress *state, unsigned char **lh, const unsigned char *max) |
|||
{ |
|||
while(*lh < max) |
|||
{ |
|||
(*lh)++; |
|||
update_hash(state, *lh); |
|||
} |
|||
} |
|||
#endif |
|||
|
|||
static size_t qlz_compress_core(const unsigned char *source, unsigned char *destination, size_t size, qlz_state_compress *state) |
|||
{ |
|||
const unsigned char *last_byte = source + size - 1; |
|||
const unsigned char *src = source; |
|||
unsigned char *cword_ptr = destination; |
|||
unsigned char *dst = destination + CWORD_LEN; |
|||
ui32 cword_val = 1U << 31; |
|||
const unsigned char *last_matchstart = last_byte - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END; |
|||
ui32 fetch = 0; |
|||
unsigned int lits = 0; |
|||
|
|||
(void) lits; |
|||
|
|||
if(src <= last_matchstart) |
|||
fetch = fast_read(src, 3); |
|||
|
|||
while(src <= last_matchstart) |
|||
{ |
|||
if ((cword_val & 1) == 1) |
|||
{ |
|||
// store uncompressed if compression ratio is too low |
|||
if (src > source + (size >> 1) && dst - destination > src - source - ((src - source) >> 5)) |
|||
return 0; |
|||
|
|||
fast_write((cword_val >> 1) | (1U << 31), cword_ptr, CWORD_LEN); |
|||
|
|||
cword_ptr = dst; |
|||
dst += CWORD_LEN; |
|||
cword_val = 1U << 31; |
|||
fetch = fast_read(src, 3); |
|||
} |
|||
#if QLZ_COMPRESSION_LEVEL == 1 |
|||
{ |
|||
const unsigned char *o; |
|||
ui32 hash, cached; |
|||
|
|||
hash = hash_func(fetch); |
|||
cached = fetch ^ state->hash[hash].cache; |
|||
state->hash[hash].cache = fetch; |
|||
|
|||
o = state->hash[hash].offset + OFFSET_BASE; |
|||
state->hash[hash].offset = CAST(src - OFFSET_BASE); |
|||
|
|||
#ifdef X86X64 |
|||
if ((cached & 0xffffff) == 0 && o != OFFSET_BASE && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > source + 3 && same(src - 3, 6)))) |
|||
{ |
|||
if(cached != 0) |
|||
{ |
|||
#else |
|||
if (cached == 0 && o != OFFSET_BASE && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > source + 3 && same(src - 3, 6)))) |
|||
{ |
|||
if (*(o + 3) != *(src + 3)) |
|||
{ |
|||
#endif |
|||
hash <<= 4; |
|||
cword_val = (cword_val >> 1) | (1U << 31); |
|||
fast_write((3 - 2) | hash, dst, 2); |
|||
src += 3; |
|||
dst += 2; |
|||
} |
|||
else |
|||
{ |
|||
const unsigned char *old_src = src; |
|||
size_t matchlen; |
|||
hash <<= 4; |
|||
|
|||
cword_val = (cword_val >> 1) | (1U << 31); |
|||
src += 4; |
|||
|
|||
if(*(o + (src - old_src)) == *src) |
|||
{ |
|||
src++; |
|||
if(*(o + (src - old_src)) == *src) |
|||
{ |
|||
size_t q = last_byte - UNCOMPRESSED_END - (src - 5) + 1; |
|||
size_t remaining = q > 255 ? 255 : q; |
|||
src++; |
|||
while(*(o + (src - old_src)) == *src && (size_t)(src - old_src) < remaining) |
|||
src++; |
|||
} |
|||
} |
|||
|
|||
matchlen = src - old_src; |
|||
if (matchlen < 18) |
|||
{ |
|||
fast_write((ui32)(matchlen - 2) | hash, dst, 2); |
|||
dst += 2; |
|||
} |
|||
else |
|||
{ |
|||
fast_write((ui32)(matchlen << 16) | hash, dst, 3); |
|||
dst += 3; |
|||
} |
|||
} |
|||
fetch = fast_read(src, 3); |
|||
lits = 0; |
|||
} |
|||
else |
|||
{ |
|||
lits++; |
|||
*dst = *src; |
|||
src++; |
|||
dst++; |
|||
cword_val = (cword_val >> 1); |
|||
#ifdef X86X64 |
|||
fetch = fast_read(src, 3); |
|||
#else |
|||
fetch = (fetch >> 8 & 0xffff) | (*(src + 2) << 16); |
|||
#endif |
|||
} |
|||
} |
|||
#elif QLZ_COMPRESSION_LEVEL >= 2 |
|||
{ |
|||
const unsigned char *o, *offset2; |
|||
ui32 hash, matchlen, k, m, best_k = 0; |
|||
unsigned char c; |
|||
size_t remaining = (last_byte - UNCOMPRESSED_END - src + 1) > 255 ? 255 : (last_byte - UNCOMPRESSED_END - src + 1); |
|||
(void)best_k; |
|||
|
|||
|
|||
//hash = hashat(src); |
|||
fetch = fast_read(src, 3); |
|||
hash = hash_func(fetch); |
|||
|
|||
c = state->hash_counter[hash]; |
|||
|
|||
offset2 = state->hash[hash].offset[0]; |
|||
if(offset2 < src - MINOFFSET && c > 0 && ((fast_read(offset2, 3) ^ fetch) & 0xffffff) == 0) |
|||
{ |
|||
matchlen = 3; |
|||
if(*(offset2 + matchlen) == *(src + matchlen)) |
|||
{ |
|||
matchlen = 4; |
|||
while(*(offset2 + matchlen) == *(src + matchlen) && matchlen < remaining) |
|||
matchlen++; |
|||
} |
|||
} |
|||
else |
|||
matchlen = 0; |
|||
for(k = 1; k < QLZ_POINTERS && c > k; k++) |
|||
{ |
|||
o = state->hash[hash].offset[k]; |
|||
#if QLZ_COMPRESSION_LEVEL == 3 |
|||
if(((fast_read(o, 3) ^ fetch) & 0xffffff) == 0 && o < src - MINOFFSET) |
|||
#elif QLZ_COMPRESSION_LEVEL == 2 |
|||
if(*(src + matchlen) == *(o + matchlen) && ((fast_read(o, 3) ^ fetch) & 0xffffff) == 0 && o < src - MINOFFSET) |
|||
#endif |
|||
{ |
|||
m = 3; |
|||
while(*(o + m) == *(src + m) && m < remaining) |
|||
m++; |
|||
#if QLZ_COMPRESSION_LEVEL == 3 |
|||
if ((m > matchlen) || (m == matchlen && o > offset2)) |
|||
#elif QLZ_COMPRESSION_LEVEL == 2 |
|||
if (m > matchlen) |
|||
#endif |
|||
{ |
|||
offset2 = o; |
|||
matchlen = m; |
|||
best_k = k; |
|||
} |
|||
} |
|||
} |
|||
o = offset2; |
|||
state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = src; |
|||
c++; |
|||
state->hash_counter[hash] = c; |
|||
|
|||
#if QLZ_COMPRESSION_LEVEL == 3 |
|||
if(matchlen > 2 && src - o < 131071) |
|||
{ |
|||
ui32 u; |
|||
size_t offset = src - o; |
|||
|
|||
for(u = 1; u < matchlen; u++) |
|||
{ |
|||
hash = hashat(src + u); |
|||
c = state->hash_counter[hash]++; |
|||
state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = src + u; |
|||
} |
|||
|
|||
cword_val = (cword_val >> 1) | (1U << 31); |
|||
src += matchlen; |
|||
|
|||
if(matchlen == 3 && offset <= 63) |
|||
{ |
|||
*dst = (unsigned char)(offset << 2); |
|||
dst++; |
|||
} |
|||
else if (matchlen == 3 && offset <= 16383) |
|||
{ |
|||
ui32 f = (ui32)((offset << 2) | 1); |
|||
fast_write(f, dst, 2); |
|||
dst += 2; |
|||
} |
|||
else if (matchlen <= 18 && offset <= 1023) |
|||
{ |
|||
ui32 f = ((matchlen - 3) << 2) | ((ui32)offset << 6) | 2; |
|||
fast_write(f, dst, 2); |
|||
dst += 2; |
|||
} |
|||
|
|||
else if(matchlen <= 33) |
|||
{ |
|||
ui32 f = ((matchlen - 2) << 2) | ((ui32)offset << 7) | 3; |
|||
fast_write(f, dst, 3); |
|||
dst += 3; |
|||
} |
|||
else |
|||
{ |
|||
ui32 f = ((matchlen - 3) << 7) | ((ui32)offset << 15) | 3; |
|||
fast_write(f, dst, 4); |
|||
dst += 4; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
*dst = *src; |
|||
src++; |
|||
dst++; |
|||
cword_val = (cword_val >> 1); |
|||
} |
|||
#elif QLZ_COMPRESSION_LEVEL == 2 |
|||
|
|||
if(matchlen > 2) |
|||
{ |
|||
cword_val = (cword_val >> 1) | (1U << 31); |
|||
src += matchlen; |
|||
|
|||
if (matchlen < 10) |
|||
{ |
|||
ui32 f = best_k | ((matchlen - 2) << 2) | (hash << 5); |
|||
fast_write(f, dst, 2); |
|||
dst += 2; |
|||
} |
|||
else |
|||
{ |
|||
ui32 f = best_k | (matchlen << 16) | (hash << 5); |
|||
fast_write(f, dst, 3); |
|||
dst += 3; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
*dst = *src; |
|||
src++; |
|||
dst++; |
|||
cword_val = (cword_val >> 1); |
|||
} |
|||
#endif |
|||
} |
|||
#endif |
|||
} |
|||
while (src <= last_byte) |
|||
{ |
|||
if ((cword_val & 1) == 1) |
|||
{ |
|||
fast_write((cword_val >> 1) | (1U << 31), cword_ptr, CWORD_LEN); |
|||
cword_ptr = dst; |
|||
dst += CWORD_LEN; |
|||
cword_val = 1U << 31; |
|||
} |
|||
#if QLZ_COMPRESSION_LEVEL < 3 |
|||
if (src <= last_byte - 3) |
|||
{ |
|||
#if QLZ_COMPRESSION_LEVEL == 1 |
|||
ui32 hash, fetch; |
|||
fetch = fast_read(src, 3); |
|||
hash = hash_func(fetch); |
|||
state->hash[hash].offset = CAST(src - OFFSET_BASE); |
|||
state->hash[hash].cache = fetch; |
|||
#elif QLZ_COMPRESSION_LEVEL == 2 |
|||
ui32 hash; |
|||
unsigned char c; |
|||
hash = hashat(src); |
|||
c = state->hash_counter[hash]; |
|||
state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = src; |
|||
c++; |
|||
state->hash_counter[hash] = c; |
|||
#endif |
|||
} |
|||
#endif |
|||
*dst = *src; |
|||
src++; |
|||
dst++; |
|||
cword_val = (cword_val >> 1); |
|||
} |
|||
|
|||
while((cword_val & 1) != 1) |
|||
cword_val = (cword_val >> 1); |
|||
|
|||
fast_write((cword_val >> 1) | (1U << 31), cword_ptr, CWORD_LEN); |
|||
|
|||
// min. size must be 9 bytes so that the qlz_size functions can take 9 bytes as argument |
|||
return dst - destination < 9 ? 9 : dst - destination; |
|||
} |
|||
|
|||
static size_t qlz_decompress_core(const unsigned char *source, unsigned char *destination, size_t size, qlz_state_decompress *state, const unsigned char *history) |
|||
{ |
|||
const unsigned char *src = source + qlz_size_header((const char *)source); |
|||
unsigned char *dst = destination; |
|||
const unsigned char *last_destination_byte = destination + size - 1; |
|||
ui32 cword_val = 1; |
|||
const unsigned char *last_matchstart = last_destination_byte - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END; |
|||
unsigned char *last_hashed = destination - 1; |
|||
const unsigned char *last_source_byte = source + qlz_size_compressed((const char *)source) - 1; |
|||
static const ui32 bitlut[16] = {4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0}; |
|||
|
|||
(void) last_source_byte; |
|||
(void) last_hashed; |
|||
(void) state; |
|||
(void) history; |
|||
|
|||
for(;;) |
|||
{ |
|||
ui32 fetch; |
|||
|
|||
if (cword_val == 1) |
|||
{ |
|||
#ifdef QLZ_MEMORY_SAFE |
|||
if(src + CWORD_LEN - 1 > last_source_byte) |
|||
return 0; |
|||
#endif |
|||
cword_val = fast_read(src, CWORD_LEN); |
|||
src += CWORD_LEN; |
|||
} |
|||
|
|||
#ifdef QLZ_MEMORY_SAFE |
|||
if(src + 4 - 1 > last_source_byte) |
|||
return 0; |
|||
#endif |
|||
|
|||
fetch = fast_read(src, 4); |
|||
|
|||
if ((cword_val & 1) == 1) |
|||
{ |
|||
ui32 matchlen; |
|||
const unsigned char *offset2; |
|||
|
|||
#if QLZ_COMPRESSION_LEVEL == 1 |
|||
ui32 hash; |
|||
cword_val = cword_val >> 1; |
|||
hash = (fetch >> 4) & 0xfff; |
|||
offset2 = (const unsigned char *)(size_t)state->hash[hash].offset; |
|||
|
|||
if((fetch & 0xf) != 0) |
|||
{ |
|||
matchlen = (fetch & 0xf) + 2; |
|||
src += 2; |
|||
} |
|||
else |
|||
{ |
|||
matchlen = *(src + 2); |
|||
src += 3; |
|||
} |
|||
|
|||
#elif QLZ_COMPRESSION_LEVEL == 2 |
|||
ui32 hash; |
|||
unsigned char c; |
|||
cword_val = cword_val >> 1; |
|||
hash = (fetch >> 5) & 0x7ff; |
|||
c = (unsigned char)(fetch & 0x3); |
|||
offset2 = state->hash[hash].offset[c]; |
|||
|
|||
if((fetch & (28)) != 0) |
|||
{ |
|||
matchlen = ((fetch >> 2) & 0x7) + 2; |
|||
src += 2; |
|||
} |
|||
else |
|||
{ |
|||
matchlen = *(src + 2); |
|||
src += 3; |
|||
} |
|||
|
|||
#elif QLZ_COMPRESSION_LEVEL == 3 |
|||
ui32 offset; |
|||
cword_val = cword_val >> 1; |
|||
if ((fetch & 3) == 0) |
|||
{ |
|||
offset = (fetch & 0xff) >> 2; |
|||
matchlen = 3; |
|||
src++; |
|||
} |
|||
else if ((fetch & 2) == 0) |
|||
{ |
|||
offset = (fetch & 0xffff) >> 2; |
|||
matchlen = 3; |
|||
src += 2; |
|||
} |
|||
else if ((fetch & 1) == 0) |
|||
{ |
|||
offset = (fetch & 0xffff) >> 6; |
|||
matchlen = ((fetch >> 2) & 15) + 3; |
|||
src += 2; |
|||
} |
|||
else if ((fetch & 127) != 3) |
|||
{ |
|||
offset = (fetch >> 7) & 0x1ffff; |
|||
matchlen = ((fetch >> 2) & 0x1f) + 2; |
|||
src += 3; |
|||
} |
|||
else |
|||
{ |
|||
offset = (fetch >> 15); |
|||
matchlen = ((fetch >> 7) & 255) + 3; |
|||
src += 4; |
|||
} |
|||
|
|||
offset2 = dst - offset; |
|||
#endif |
|||
|
|||
#ifdef QLZ_MEMORY_SAFE |
|||
if(offset2 < history || offset2 > dst - MINOFFSET - 1) |
|||
return 0; |
|||
|
|||
if(matchlen > (ui32)(last_destination_byte - dst - UNCOMPRESSED_END + 1)) |
|||
return 0; |
|||
#endif |
|||
|
|||
memcpy_up(dst, offset2, matchlen); |
|||
dst += matchlen; |
|||
|
|||
#if QLZ_COMPRESSION_LEVEL <= 2 |
|||
update_hash_upto(state, &last_hashed, dst - matchlen); |
|||
last_hashed = dst - 1; |
|||
#endif |
|||
} |
|||
else |
|||
{ |
|||
if (dst < last_matchstart) |
|||
{ |
|||
unsigned int n = bitlut[cword_val & 0xf]; |
|||
#ifdef X86X64 |
|||
*(ui32 *)dst = *(ui32 *)src; |
|||
#else |
|||
memcpy_up(dst, src, 4); |
|||
#endif |
|||
cword_val = cword_val >> n; |
|||
dst += n; |
|||
src += n; |
|||
#if QLZ_COMPRESSION_LEVEL <= 2 |
|||
update_hash_upto(state, &last_hashed, dst - 3); |
|||
#endif |
|||
} |
|||
else |
|||
{ |
|||
while(dst <= last_destination_byte) |
|||
{ |
|||
if (cword_val == 1) |
|||
{ |
|||
src += CWORD_LEN; |
|||
cword_val = 1U << 31; |
|||
} |
|||
#ifdef QLZ_MEMORY_SAFE |
|||
if(src >= last_source_byte + 1) |
|||
return 0; |
|||
#endif |
|||
*dst = *src; |
|||
dst++; |
|||
src++; |
|||
cword_val = cword_val >> 1; |
|||
} |
|||
|
|||
#if QLZ_COMPRESSION_LEVEL <= 2 |
|||
update_hash_upto(state, &last_hashed, last_destination_byte - 3); // todo, use constant |
|||
#endif |
|||
return size; |
|||
} |
|||
|
|||
} |
|||
} |
|||
} |
|||
|
|||
size_t qlz_compress(const void *source, char *destination, size_t size, qlz_state_compress *state) |
|||
{ |
|||
size_t r; |
|||
ui32 compressed; |
|||
size_t base; |
|||
|
|||
if(size == 0 || size > 0xffffffff - 400) |
|||
return 0; |
|||
|
|||
if(size < 216) |
|||
base = 3; |
|||
else |
|||
base = 9; |
|||
|
|||
#if QLZ_STREAMING_BUFFER > 0 |
|||
if (state->stream_counter + size - 1 >= QLZ_STREAMING_BUFFER) |
|||
#endif |
|||
{ |
|||
reset_table_compress(state); |
|||
r = base + qlz_compress_core((const unsigned char *)source, (unsigned char*)destination + base, size, state); |
|||
#if QLZ_STREAMING_BUFFER > 0 |
|||
reset_table_compress(state); |
|||
#endif |
|||
if(r == base) |
|||
{ |
|||
memcpy(destination + base, source, size); |
|||
r = size + base; |
|||
compressed = 0; |
|||
} |
|||
else |
|||
{ |
|||
compressed = 1; |
|||
} |
|||
state->stream_counter = 0; |
|||
} |
|||
#if QLZ_STREAMING_BUFFER > 0 |
|||
else |
|||
{ |
|||
unsigned char *src = state->stream_buffer + state->stream_counter; |
|||
|
|||
memcpy(src, source, size); |
|||
r = base + qlz_compress_core(src, (unsigned char*)destination + base, size, state); |
|||
|
|||
if(r == base) |
|||
{ |
|||
memcpy(destination + base, src, size); |
|||
r = size + base; |
|||
compressed = 0; |
|||
reset_table_compress(state); |
|||
} |
|||
else |
|||
{ |
|||
compressed = 1; |
|||
} |
|||
state->stream_counter += size; |
|||
} |
|||
#endif |
|||
if(base == 3) |
|||
{ |
|||
*destination = (unsigned char)(0 | compressed); |
|||
*(destination + 1) = (unsigned char)r; |
|||
*(destination + 2) = (unsigned char)size; |
|||
} |
|||
else |
|||
{ |
|||
*destination = (unsigned char)(2 | compressed); |
|||
fast_write((ui32)r, destination + 1, 4); |
|||
fast_write((ui32)size, destination + 5, 4); |
|||
} |
|||
|
|||
*destination |= (QLZ_COMPRESSION_LEVEL << 2); |
|||
*destination |= (1 << 6); |
|||
*destination |= ((QLZ_STREAMING_BUFFER == 0 ? 0 : (QLZ_STREAMING_BUFFER == 100000 ? 1 : (QLZ_STREAMING_BUFFER == 1000000 ? 2 : 3))) << 4); |
|||
|
|||
// 76543210 |
|||
// 01SSLLHC |
|||
|
|||
return r; |
|||
} |
|||
|
|||
size_t qlz_decompress(const char *source, void *destination, qlz_state_decompress *state) |
|||
{ |
|||
size_t dsiz = qlz_size_decompressed(source); |
|||
|
|||
#if QLZ_STREAMING_BUFFER > 0 |
|||
if (state->stream_counter + qlz_size_decompressed(source) - 1 >= QLZ_STREAMING_BUFFER) |
|||
#endif |
|||
{ |
|||
if((*source & 1) == 1) |
|||
{ |
|||
reset_table_decompress(state); |
|||
dsiz = qlz_decompress_core((const unsigned char *)source, (unsigned char *)destination, dsiz, state, (const unsigned char *)destination); |
|||
} |
|||
else |
|||
{ |
|||
memcpy(destination, source + qlz_size_header(source), dsiz); |
|||
} |
|||
state->stream_counter = 0; |
|||
reset_table_decompress(state); |
|||
} |
|||
#if QLZ_STREAMING_BUFFER > 0 |
|||
else |
|||
{ |
|||
unsigned char *dst = state->stream_buffer + state->stream_counter; |
|||
if((*source & 1) == 1) |
|||
{ |
|||
dsiz = qlz_decompress_core((const unsigned char *)source, dst, dsiz, state, (const unsigned char *)state->stream_buffer); |
|||
} |
|||
else |
|||
{ |
|||
memcpy(dst, source + qlz_size_header(source), dsiz); |
|||
reset_table_decompress(state); |
|||
} |
|||
memcpy(destination, dst, dsiz); |
|||
state->stream_counter += dsiz; |
|||
} |
|||
#endif |
|||
return dsiz; |
|||
} |
|||
|
@ -0,0 +1,144 @@ |
|||
#ifndef QLZ_HEADER |
|||
#define QLZ_HEADER |
|||
|
|||
// Fast data compression library |
|||
// Copyright (C) 2006-2011 Lasse Mikkel Reinhold |
|||
// lar@quicklz.com |
|||
// |
|||
// QuickLZ can be used for free under the GPL 1, 2 or 3 license (where anything |
|||
// released into public must be open source) or under a commercial license if such |
|||
// has been acquired (see http://www.quicklz.com/order.html). The commercial license |
|||
// does not cover derived or ported versions created by third parties under GPL. |
|||
|
|||
// You can edit following user settings. Data must be decompressed with the same |
|||
// setting of QLZ_COMPRESSION_LEVEL and QLZ_STREAMING_BUFFER as it was compressed |
|||
// (see manual). If QLZ_STREAMING_BUFFER > 0, scratch buffers must be initially |
|||
// zeroed out (see manual). First #ifndef makes it possible to define settings from |
|||
// the outside like the compiler command line. |
|||
|
|||
// 1.5.0 final |
|||
|
|||
#ifndef QLZ_COMPRESSION_LEVEL |
|||
#define QLZ_COMPRESSION_LEVEL 1 |
|||
//#define QLZ_COMPRESSION_LEVEL 2 |
|||
//#define QLZ_COMPRESSION_LEVEL 3 |
|||
|
|||
#define QLZ_STREAMING_BUFFER 0 |
|||
//#define QLZ_STREAMING_BUFFER 100000 |
|||
//#define QLZ_STREAMING_BUFFER 1000000 |
|||
|
|||
//#define QLZ_MEMORY_SAFE |
|||
#endif |
|||
|
|||
#define QLZ_VERSION_MAJOR 1 |
|||
#define QLZ_VERSION_MINOR 5 |
|||
#define QLZ_VERSION_REVISION 0 |
|||
|
|||
// Using size_t, memset() and memcpy() |
|||
#include <string.h> |
|||
|
|||
// Verify compression level |
|||
#if QLZ_COMPRESSION_LEVEL != 1 && QLZ_COMPRESSION_LEVEL != 2 && QLZ_COMPRESSION_LEVEL != 3 |
|||
#error QLZ_COMPRESSION_LEVEL must be 1, 2 or 3 |
|||
#endif |
|||
|
|||
typedef unsigned int ui32; |
|||
typedef unsigned short int ui16; |
|||
|
|||
// Decrease QLZ_POINTERS for level 3 to increase compression speed. Do not touch any other values! |
|||
#if QLZ_COMPRESSION_LEVEL == 1 |
|||
#define QLZ_POINTERS 1 |
|||
#define QLZ_HASH_VALUES 4096 |
|||
#elif QLZ_COMPRESSION_LEVEL == 2 |
|||
#define QLZ_POINTERS 4 |
|||
#define QLZ_HASH_VALUES 2048 |
|||
#elif QLZ_COMPRESSION_LEVEL == 3 |
|||
#define QLZ_POINTERS 16 |
|||
#define QLZ_HASH_VALUES 4096 |
|||
#endif |
|||
|
|||
// Detect if pointer size is 64-bit. It's not fatal if some 64-bit target is not detected because this is only for adding an optional 64-bit optimization. |
|||
#if defined _LP64 || defined __LP64__ || defined __64BIT__ || _ADDR64 || defined _WIN64 || defined __arch64__ || __WORDSIZE == 64 || (defined __sparc && defined __sparcv9) || defined __x86_64 || defined __amd64 || defined __x86_64__ || defined _M_X64 || defined _M_IA64 || defined __ia64 || defined __IA64__ |
|||
#define QLZ_PTR_64 |
|||
#endif |
|||
|
|||
// hash entry |
|||
typedef struct |
|||
{ |
|||
#if QLZ_COMPRESSION_LEVEL == 1 |
|||
ui32 cache; |
|||
#if defined QLZ_PTR_64 && QLZ_STREAMING_BUFFER == 0 |
|||
unsigned int offset; |
|||
#else |
|||
const unsigned char *offset; |
|||
#endif |
|||
#else |
|||
const unsigned char *offset[QLZ_POINTERS]; |
|||
#endif |
|||
|
|||
} qlz_hash_compress; |
|||
|
|||
typedef struct |
|||
{ |
|||
#if QLZ_COMPRESSION_LEVEL == 1 |
|||
const unsigned char *offset; |
|||
#else |
|||
const unsigned char *offset[QLZ_POINTERS]; |
|||
#endif |
|||
} qlz_hash_decompress; |
|||
|
|||
|
|||
// states |
|||
typedef struct |
|||
{ |
|||
#if QLZ_STREAMING_BUFFER > 0 |
|||
unsigned char stream_buffer[QLZ_STREAMING_BUFFER]; |
|||
#endif |
|||
size_t stream_counter; |
|||
qlz_hash_compress hash[QLZ_HASH_VALUES]; |
|||
unsigned char hash_counter[QLZ_HASH_VALUES]; |
|||
} qlz_state_compress; |
|||
|
|||
|
|||
#if QLZ_COMPRESSION_LEVEL == 1 || QLZ_COMPRESSION_LEVEL == 2 |
|||
typedef struct |
|||
{ |
|||
#if QLZ_STREAMING_BUFFER > 0 |
|||
unsigned char stream_buffer[QLZ_STREAMING_BUFFER]; |
|||
#endif |
|||
qlz_hash_decompress hash[QLZ_HASH_VALUES]; |
|||
unsigned char hash_counter[QLZ_HASH_VALUES]; |
|||
size_t stream_counter; |
|||
} qlz_state_decompress; |
|||
#elif QLZ_COMPRESSION_LEVEL == 3 |
|||
typedef struct |
|||
{ |
|||
#if QLZ_STREAMING_BUFFER > 0 |
|||
unsigned char stream_buffer[QLZ_STREAMING_BUFFER]; |
|||
#endif |
|||
#if QLZ_COMPRESSION_LEVEL <= 2 |
|||
qlz_hash_decompress hash[QLZ_HASH_VALUES]; |
|||
#endif |
|||
size_t stream_counter; |
|||
} qlz_state_decompress; |
|||
#endif |
|||
|
|||
|
|||
#if defined (__cplusplus) |
|||
extern "C" { |
|||
#endif |
|||
|
|||
// Public functions of QuickLZ |
|||
size_t qlz_size_decompressed(const char *source); |
|||
size_t qlz_size_compressed(const char *source); |
|||
size_t qlz_compress(const void *source, char *destination, size_t size, qlz_state_compress *state); |
|||
size_t qlz_decompress(const char *source, void *destination, qlz_state_decompress *state); |
|||
int qlz_get_setting(int setting); |
|||
size_t qlz_size_header(const char *source); |
|||
|
|||
#if defined (__cplusplus) |
|||
} |
|||
#endif |
|||
|
|||
#endif |
|||
|
@ -0,0 +1,206 @@ |
|||
/******************************************************
|
|||
XtraBackup: hot backup tool for InnoDB |
|||
(c) 2009-2012 Percona Inc. |
|||
Originally Created 3/3/2009 Yasufumi Kinoshita |
|||
Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko, |
|||
Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
/* Data file read filter implementation */ |
|||
|
|||
#include "read_filt.h"
|
|||
#include "common.h"
|
|||
#include "fil_cur.h"
|
|||
#include "xtrabackup.h"
|
|||
|
|||
/****************************************************************//**
|
|||
Perform read filter context initialization that is common to all read |
|||
filters. */ |
|||
static |
|||
void |
|||
common_init( |
|||
/*========*/ |
|||
xb_read_filt_ctxt_t* ctxt, /*!<in/out: read filter context */ |
|||
const xb_fil_cur_t* cursor) /*!<in: file cursor */ |
|||
{ |
|||
ctxt->offset = 0; |
|||
ctxt->data_file_size = cursor->statinfo.st_size; |
|||
ctxt->buffer_capacity = cursor->buf_size; |
|||
ctxt->page_size = cursor->page_size; |
|||
} |
|||
|
|||
/****************************************************************//**
|
|||
Initialize the pass-through read filter. */ |
|||
static |
|||
void |
|||
rf_pass_through_init( |
|||
/*=================*/ |
|||
xb_read_filt_ctxt_t* ctxt, /*!<in/out: read filter context */ |
|||
const xb_fil_cur_t* cursor, /*!<in: file cursor */ |
|||
ulint space_id __attribute__((unused))) |
|||
/*!<in: space id we are reading */ |
|||
{ |
|||
common_init(ctxt, cursor); |
|||
} |
|||
|
|||
/****************************************************************//**
|
|||
Get the next batch of pages for the pass-through read filter. */ |
|||
static |
|||
void |
|||
rf_pass_through_get_next_batch( |
|||
/*===========================*/ |
|||
xb_read_filt_ctxt_t* ctxt, /*!<in/out: read filter
|
|||
context */ |
|||
ib_int64_t* read_batch_start, /*!<out: starting read
|
|||
offset in bytes for the |
|||
next batch of pages */ |
|||
ib_int64_t* read_batch_len) /*!<out: length in
|
|||
bytes of the next batch |
|||
of pages */ |
|||
{ |
|||
*read_batch_start = ctxt->offset; |
|||
*read_batch_len = ctxt->data_file_size - ctxt->offset; |
|||
|
|||
if (*read_batch_len > (ib_int64_t)ctxt->buffer_capacity) { |
|||
*read_batch_len = ctxt->buffer_capacity; |
|||
} |
|||
|
|||
ctxt->offset += *read_batch_len; |
|||
} |
|||
|
|||
/****************************************************************//**
|
|||
Deinitialize the pass-through read filter. */ |
|||
static |
|||
void |
|||
rf_pass_through_deinit( |
|||
/*===================*/ |
|||
xb_read_filt_ctxt_t* ctxt __attribute__((unused))) |
|||
/*!<in: read filter context */ |
|||
{ |
|||
} |
|||
|
|||
/****************************************************************//**
|
|||
Initialize the changed page bitmap-based read filter. Assumes that |
|||
the bitmap is already set up in changed_page_bitmap. */ |
|||
static |
|||
void |
|||
rf_bitmap_init( |
|||
/*===========*/ |
|||
xb_read_filt_ctxt_t* ctxt, /*!<in/out: read filter
|
|||
context */ |
|||
const xb_fil_cur_t* cursor, /*!<in: read cursor */ |
|||
ulint space_id) /*!<in: space id */ |
|||
{ |
|||
common_init(ctxt, cursor); |
|||
ctxt->bitmap_range = xb_page_bitmap_range_init(changed_page_bitmap, |
|||
space_id); |
|||
ctxt->filter_batch_end = 0; |
|||
} |
|||
|
|||
/****************************************************************//**
|
|||
Get the next batch of pages for the bitmap read filter. */ |
|||
static |
|||
void |
|||
rf_bitmap_get_next_batch( |
|||
/*=====================*/ |
|||
xb_read_filt_ctxt_t* ctxt, /*!<in/out: read filter
|
|||
context */ |
|||
ib_int64_t* read_batch_start, /*!<out: starting read
|
|||
offset in bytes for the |
|||
next batch of pages */ |
|||
ib_int64_t* read_batch_len) /*!<out: length in
|
|||
bytes of the next batch |
|||
of pages */ |
|||
{ |
|||
ulint start_page_id; |
|||
|
|||
start_page_id = (ulint)(ctxt->offset / ctxt->page_size); |
|||
|
|||
xb_a (ctxt->offset % ctxt->page_size == 0); |
|||
|
|||
if (start_page_id == ctxt->filter_batch_end) { |
|||
|
|||
/* Used up all the previous bitmap range, get some more */ |
|||
ulint next_page_id; |
|||
|
|||
/* Find the next changed page using the bitmap */ |
|||
next_page_id = xb_page_bitmap_range_get_next_bit |
|||
(ctxt->bitmap_range, TRUE); |
|||
|
|||
if (next_page_id == ULINT_UNDEFINED) { |
|||
*read_batch_len = 0; |
|||
return; |
|||
} |
|||
|
|||
ctxt->offset = next_page_id * ctxt->page_size; |
|||
|
|||
/* Find the end of the current changed page block by searching
|
|||
for the next cleared bitmap bit */ |
|||
ctxt->filter_batch_end |
|||
= xb_page_bitmap_range_get_next_bit(ctxt->bitmap_range, |
|||
FALSE); |
|||
xb_a(next_page_id < ctxt->filter_batch_end); |
|||
} |
|||
|
|||
*read_batch_start = ctxt->offset; |
|||
if (ctxt->filter_batch_end == ULINT_UNDEFINED) { |
|||
/* No more cleared bits in the bitmap, need to copy all the
|
|||
remaining pages. */ |
|||
*read_batch_len = ctxt->data_file_size - ctxt->offset; |
|||
} else { |
|||
*read_batch_len = ctxt->filter_batch_end * ctxt->page_size |
|||
- ctxt->offset; |
|||
} |
|||
|
|||
/* If the page block is larger than the buffer capacity, limit it to
|
|||
buffer capacity. The subsequent invocations will continue returning |
|||
the current block in buffer-sized pieces until ctxt->filter_batch_end |
|||
is reached, trigerring the next bitmap query. */ |
|||
if (*read_batch_len > (ib_int64_t)ctxt->buffer_capacity) { |
|||
*read_batch_len = ctxt->buffer_capacity; |
|||
} |
|||
|
|||
ctxt->offset += *read_batch_len; |
|||
xb_a (ctxt->offset % ctxt->page_size == 0); |
|||
xb_a (*read_batch_start % ctxt->page_size == 0); |
|||
xb_a (*read_batch_len % ctxt->page_size == 0); |
|||
} |
|||
|
|||
/****************************************************************//**
|
|||
Deinitialize the changed page bitmap-based read filter. */ |
|||
static |
|||
void |
|||
rf_bitmap_deinit( |
|||
/*=============*/ |
|||
xb_read_filt_ctxt_t* ctxt) /*!<in/out: read filter context */ |
|||
{ |
|||
xb_page_bitmap_range_deinit(ctxt->bitmap_range); |
|||
} |
|||
|
|||
/* The pass-through read filter */ |
|||
xb_read_filt_t rf_pass_through = { |
|||
&rf_pass_through_init, |
|||
&rf_pass_through_get_next_batch, |
|||
&rf_pass_through_deinit |
|||
}; |
|||
|
|||
/* The changed page bitmap-based read filter */ |
|||
xb_read_filt_t rf_bitmap = { |
|||
&rf_bitmap_init, |
|||
&rf_bitmap_get_next_batch, |
|||
&rf_bitmap_deinit |
|||
}; |
@ -0,0 +1,62 @@ |
|||
/****************************************************** |
|||
XtraBackup: hot backup tool for InnoDB |
|||
(c) 2009-2012 Percona Inc. |
|||
Originally Created 3/3/2009 Yasufumi Kinoshita |
|||
Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko, |
|||
Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
/* Data file read filter interface */ |
|||
|
|||
#ifndef XB_READ_FILT_H |
|||
#define XB_READ_FILT_H |
|||
|
|||
#include "changed_page_bitmap.h" |
|||
|
|||
struct xb_fil_cur_t; |
|||
|
|||
/* The read filter context */ |
|||
struct xb_read_filt_ctxt_t { |
|||
ib_int64_t offset; /*!< current file offset */ |
|||
ib_int64_t data_file_size; /*!< data file size */ |
|||
size_t buffer_capacity;/*!< read buffer capacity */ |
|||
ib_int64_t space_id; /*!< space id */ |
|||
/* The following fields used only in bitmap filter */ |
|||
/* Move these to union if any other filters are added in future */ |
|||
xb_page_bitmap_range *bitmap_range; /*!< changed page bitmap range |
|||
iterator for space_id */ |
|||
size_t page_size; /*!< page size */ |
|||
ulint filter_batch_end;/*!< the ending page id of the |
|||
current changed page block in |
|||
the bitmap */ |
|||
}; |
|||
|
|||
/* The read filter */ |
|||
struct xb_read_filt_t { |
|||
void (*init)(xb_read_filt_ctxt_t* ctxt, |
|||
const xb_fil_cur_t* cursor, |
|||
ulint space_id); |
|||
void (*get_next_batch)(xb_read_filt_ctxt_t* ctxt, |
|||
ib_int64_t* read_batch_start, |
|||
ib_int64_t* read_batch_len); |
|||
void (*deinit)(xb_read_filt_ctxt_t* ctxt); |
|||
}; |
|||
|
|||
extern xb_read_filt_t rf_pass_through; |
|||
extern xb_read_filt_t rf_bitmap; |
|||
|
|||
#endif |
@ -0,0 +1,219 @@ |
|||
/******************************************************
|
|||
XtraBackup: hot backup tool for InnoDB |
|||
(c) 2009-2013 Percona LLC and/or its affiliates. |
|||
Originally Created 3/3/2009 Yasufumi Kinoshita |
|||
Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko, |
|||
Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
/* Page write filters implementation */ |
|||
|
|||
#include <my_base.h>
|
|||
#include "common.h"
|
|||
#include "write_filt.h"
|
|||
#include "fil_cur.h"
|
|||
#include "xtrabackup.h"
|
|||
|
|||
/************************************************************************
|
|||
Write-through page write filter. */ |
|||
static my_bool wf_wt_init(xb_write_filt_ctxt_t *ctxt, char *dst_name, |
|||
xb_fil_cur_t *cursor); |
|||
static my_bool wf_wt_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile); |
|||
|
|||
xb_write_filt_t wf_write_through = { |
|||
&wf_wt_init, |
|||
&wf_wt_process, |
|||
NULL, |
|||
NULL |
|||
}; |
|||
|
|||
/************************************************************************
|
|||
Incremental page write filter. */ |
|||
static my_bool wf_incremental_init(xb_write_filt_ctxt_t *ctxt, char *dst_name, |
|||
xb_fil_cur_t *cursor); |
|||
static my_bool wf_incremental_process(xb_write_filt_ctxt_t *ctxt, |
|||
ds_file_t *dstfile); |
|||
static my_bool wf_incremental_finalize(xb_write_filt_ctxt_t *ctxt, |
|||
ds_file_t *dstfile); |
|||
static void wf_incremental_deinit(xb_write_filt_ctxt_t *ctxt); |
|||
|
|||
xb_write_filt_t wf_incremental = { |
|||
&wf_incremental_init, |
|||
&wf_incremental_process, |
|||
&wf_incremental_finalize, |
|||
&wf_incremental_deinit |
|||
}; |
|||
|
|||
/************************************************************************
|
|||
Initialize incremental page write filter. |
|||
|
|||
@return TRUE on success, FALSE on error. */ |
|||
static my_bool |
|||
wf_incremental_init(xb_write_filt_ctxt_t *ctxt, char *dst_name, |
|||
xb_fil_cur_t *cursor) |
|||
{ |
|||
char meta_name[FN_REFLEN]; |
|||
xb_delta_info_t info; |
|||
ulint buf_size; |
|||
xb_wf_incremental_ctxt_t *cp = |
|||
&(ctxt->u.wf_incremental_ctxt); |
|||
|
|||
ctxt->cursor = cursor; |
|||
|
|||
/* allocate buffer for incremental backup (4096 pages) */ |
|||
buf_size = (cursor->page_size / 4 + 1) * cursor->page_size; |
|||
cp->delta_buf_base = static_cast<byte *>(ut_malloc(buf_size)); |
|||
memset(cp->delta_buf_base, 0, buf_size); |
|||
cp->delta_buf = static_cast<byte *> |
|||
(ut_align(cp->delta_buf_base, UNIV_PAGE_SIZE_MAX)); |
|||
|
|||
/* write delta meta info */ |
|||
snprintf(meta_name, sizeof(meta_name), "%s%s", dst_name, |
|||
XB_DELTA_INFO_SUFFIX); |
|||
info.page_size = cursor->page_size; |
|||
info.zip_size = cursor->zip_size; |
|||
info.space_id = cursor->space_id; |
|||
if (!xb_write_delta_metadata(meta_name, &info)) { |
|||
msg("[%02u] xtrabackup: Error: " |
|||
"failed to write meta info for %s\n", |
|||
cursor->thread_n, cursor->rel_path); |
|||
return(FALSE); |
|||
} |
|||
|
|||
/* change the target file name, since we are only going to write
|
|||
delta pages */ |
|||
strcat(dst_name, ".delta"); |
|||
|
|||
mach_write_to_4(cp->delta_buf, 0x78747261UL); /*"xtra"*/ |
|||
cp->npages = 1; |
|||
|
|||
return(TRUE); |
|||
} |
|||
|
|||
/************************************************************************
|
|||
Run the next batch of pages through incremental page write filter. |
|||
|
|||
@return TRUE on success, FALSE on error. */ |
|||
static my_bool |
|||
wf_incremental_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile) |
|||
{ |
|||
ulint i; |
|||
xb_fil_cur_t *cursor = ctxt->cursor; |
|||
ulint page_size = cursor->page_size; |
|||
byte *page; |
|||
xb_wf_incremental_ctxt_t *cp = &(ctxt->u.wf_incremental_ctxt); |
|||
|
|||
for (i = 0, page = cursor->buf; i < cursor->buf_npages; |
|||
i++, page += page_size) { |
|||
|
|||
if (incremental_lsn >= mach_read_from_8(page + FIL_PAGE_LSN)) { |
|||
|
|||
continue; |
|||
} |
|||
|
|||
/* updated page */ |
|||
if (cp->npages == page_size / 4) { |
|||
/* flush buffer */ |
|||
if (ds_write(dstfile, cp->delta_buf, |
|||
cp->npages * page_size)) { |
|||
return(FALSE); |
|||
} |
|||
|
|||
/* clear buffer */ |
|||
memset(cp->delta_buf, 0, page_size / 4 * page_size); |
|||
/*"xtra"*/ |
|||
mach_write_to_4(cp->delta_buf, 0x78747261UL); |
|||
cp->npages = 1; |
|||
} |
|||
|
|||
mach_write_to_4(cp->delta_buf + cp->npages * 4, |
|||
cursor->buf_page_no + i); |
|||
memcpy(cp->delta_buf + cp->npages * page_size, page, |
|||
page_size); |
|||
|
|||
cp->npages++; |
|||
} |
|||
|
|||
return(TRUE); |
|||
} |
|||
|
|||
/************************************************************************
|
|||
Flush the incremental page write filter's buffer. |
|||
|
|||
@return TRUE on success, FALSE on error. */ |
|||
static my_bool |
|||
wf_incremental_finalize(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile) |
|||
{ |
|||
xb_fil_cur_t *cursor = ctxt->cursor; |
|||
ulint page_size = cursor->page_size; |
|||
xb_wf_incremental_ctxt_t *cp = &(ctxt->u.wf_incremental_ctxt); |
|||
|
|||
if (cp->npages != page_size / 4) { |
|||
mach_write_to_4(cp->delta_buf + cp->npages * 4, 0xFFFFFFFFUL); |
|||
} |
|||
|
|||
/* Mark the final block */ |
|||
mach_write_to_4(cp->delta_buf, 0x58545241UL); /*"XTRA"*/ |
|||
|
|||
/* flush buffer */ |
|||
if (ds_write(dstfile, cp->delta_buf, cp->npages * page_size)) { |
|||
return(FALSE); |
|||
} |
|||
|
|||
return(TRUE); |
|||
} |
|||
|
|||
/************************************************************************
|
|||
Free the incremental page write filter's buffer. */ |
|||
static void |
|||
wf_incremental_deinit(xb_write_filt_ctxt_t *ctxt) |
|||
{ |
|||
xb_wf_incremental_ctxt_t *cp = &(ctxt->u.wf_incremental_ctxt); |
|||
|
|||
if (cp->delta_buf_base != NULL) { |
|||
ut_free(cp->delta_buf_base); |
|||
} |
|||
} |
|||
|
|||
/************************************************************************
|
|||
Initialize the write-through page write filter. |
|||
|
|||
@return TRUE on success, FALSE on error. */ |
|||
static my_bool |
|||
wf_wt_init(xb_write_filt_ctxt_t *ctxt, char *dst_name __attribute__((unused)), |
|||
xb_fil_cur_t *cursor) |
|||
{ |
|||
ctxt->cursor = cursor; |
|||
|
|||
return(TRUE); |
|||
} |
|||
|
|||
/************************************************************************
|
|||
Write the next batch of pages to the destination datasink. |
|||
|
|||
@return TRUE on success, FALSE on error. */ |
|||
static my_bool |
|||
wf_wt_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile) |
|||
{ |
|||
xb_fil_cur_t *cursor = ctxt->cursor; |
|||
|
|||
if (ds_write(dstfile, cursor->buf, cursor->buf_read)) { |
|||
return(FALSE); |
|||
} |
|||
|
|||
return(TRUE); |
|||
} |
@ -0,0 +1,58 @@ |
|||
/****************************************************** |
|||
XtraBackup: hot backup tool for InnoDB |
|||
(c) 2009-2013 Percona LLC and/or its affiliates. |
|||
Originally Created 3/3/2009 Yasufumi Kinoshita |
|||
Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko, |
|||
Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
/* Page write filter interface */ |
|||
|
|||
#ifndef XB_WRITE_FILT_H |
|||
#define XB_WRITE_FILT_H |
|||
|
|||
#include "fil_cur.h" |
|||
#include "datasink.h" |
|||
|
|||
/* Incremental page filter context */ |
|||
typedef struct { |
|||
byte *delta_buf_base; |
|||
byte *delta_buf; |
|||
ulint npages; |
|||
} xb_wf_incremental_ctxt_t; |
|||
|
|||
/* Page filter context used as an opaque structure by callers */ |
|||
typedef struct { |
|||
xb_fil_cur_t *cursor; |
|||
union { |
|||
xb_wf_incremental_ctxt_t wf_incremental_ctxt; |
|||
} u; |
|||
} xb_write_filt_ctxt_t; |
|||
|
|||
|
|||
typedef struct { |
|||
my_bool (*init)(xb_write_filt_ctxt_t *ctxt, char *dst_name, |
|||
xb_fil_cur_t *cursor); |
|||
my_bool (*process)(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile); |
|||
my_bool (*finalize)(xb_write_filt_ctxt_t *, ds_file_t *dstfile); |
|||
void (*deinit)(xb_write_filt_ctxt_t *); |
|||
} xb_write_filt_t; |
|||
|
|||
extern xb_write_filt_t wf_write_through; |
|||
extern xb_write_filt_t wf_incremental; |
|||
|
|||
#endif /* XB_WRITE_FILT_H */ |
@ -0,0 +1,220 @@ |
|||
/******************************************************
|
|||
Percona XtraBackup: hot backup tool for InnoDB |
|||
(c) 2009-2014 Percona LLC and/or its affiliates |
|||
Originally Created 3/3/2009 Yasufumi Kinoshita |
|||
Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko, |
|||
Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
******************************************************* |
|||
|
|||
This file incorporates work covered by the following copyright and |
|||
permission notice: |
|||
|
|||
Copyright 2010 Codership Oy <http://www.codership.com>
|
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include <mysql_version.h>
|
|||
#include <my_base.h>
|
|||
#include <handler.h>
|
|||
#include <trx0sys.h>
|
|||
|
|||
#include "common.h"
|
|||
#ifdef WITH_WSREP
|
|||
#define WSREP_XID_PREFIX "WSREPXid"
|
|||
#define WSREP_XID_PREFIX_LEN MYSQL_XID_PREFIX_LEN
|
|||
#define WSREP_XID_UUID_OFFSET 8
|
|||
#define WSREP_XID_SEQNO_OFFSET (WSREP_XID_UUID_OFFSET + sizeof(wsrep_uuid_t))
|
|||
#define WSREP_XID_GTRID_LEN (WSREP_XID_SEQNO_OFFSET + sizeof(wsrep_seqno_t))
|
|||
|
|||
/*! undefined seqno */ |
|||
#define WSREP_SEQNO_UNDEFINED (-1)
|
|||
|
|||
/*! Name of file where Galera info is stored on recovery */ |
|||
#define XB_GALERA_INFO_FILENAME "xtrabackup_galera_info"
|
|||
|
|||
/* Galera UUID type - for all unique IDs */ |
|||
typedef struct wsrep_uuid { |
|||
unsigned char data[16]; |
|||
} wsrep_uuid_t; |
|||
|
|||
/* sequence number of a writeset, etc. */ |
|||
typedef long long wsrep_seqno_t; |
|||
|
|||
/* Undefined UUID */ |
|||
static const wsrep_uuid_t WSREP_UUID_UNDEFINED = {{0,}}; |
|||
|
|||
/***********************************************************************//**
|
|||
Check if a given WSREP XID is valid. |
|||
|
|||
@return true if valid. |
|||
*/ |
|||
static |
|||
bool |
|||
wsrep_is_wsrep_xid( |
|||
/*===============*/ |
|||
const void* xid_ptr) |
|||
{ |
|||
const XID* xid = reinterpret_cast<const XID*>(xid_ptr); |
|||
|
|||
return((xid->formatID == 1 && |
|||
xid->gtrid_length == WSREP_XID_GTRID_LEN && |
|||
xid->bqual_length == 0 && |
|||
!memcmp(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN))); |
|||
} |
|||
|
|||
/***********************************************************************//**
|
|||
Retrieve binary WSREP UUID from XID. |
|||
|
|||
@return binary WSREP UUID represenataion, if UUID is valid, or |
|||
WSREP_UUID_UNDEFINED otherwise. |
|||
*/ |
|||
static |
|||
const wsrep_uuid_t* |
|||
wsrep_xid_uuid( |
|||
/*===========*/ |
|||
const XID* xid) |
|||
{ |
|||
if (wsrep_is_wsrep_xid(xid)) { |
|||
return(reinterpret_cast<const wsrep_uuid_t*> |
|||
(xid->data + WSREP_XID_UUID_OFFSET)); |
|||
} else { |
|||
return(&WSREP_UUID_UNDEFINED); |
|||
} |
|||
} |
|||
|
|||
/***********************************************************************//**
|
|||
Retrieve WSREP seqno from XID. |
|||
|
|||
@return WSREP seqno, if it is valid, or WSREP_SEQNO_UNDEFINED otherwise. |
|||
*/ |
|||
wsrep_seqno_t wsrep_xid_seqno( |
|||
/*==========================*/ |
|||
const XID* xid) |
|||
{ |
|||
if (wsrep_is_wsrep_xid(xid)) { |
|||
wsrep_seqno_t seqno; |
|||
memcpy(&seqno, xid->data + WSREP_XID_SEQNO_OFFSET, |
|||
sizeof(wsrep_seqno_t)); |
|||
|
|||
return(seqno); |
|||
} else { |
|||
return(WSREP_SEQNO_UNDEFINED); |
|||
} |
|||
} |
|||
|
|||
/***********************************************************************//**
|
|||
Write UUID to string. |
|||
|
|||
@return length of UUID string representation or -EMSGSIZE if string is too |
|||
short. |
|||
*/ |
|||
static |
|||
int |
|||
wsrep_uuid_print( |
|||
/*=============*/ |
|||
const wsrep_uuid_t* uuid, |
|||
char* str, |
|||
size_t str_len) |
|||
{ |
|||
if (str_len > 36) { |
|||
const unsigned char* u = uuid->data; |
|||
return snprintf(str, str_len, |
|||
"%02x%02x%02x%02x-%02x%02x-%02x%02x-" |
|||
"%02x%02x-%02x%02x%02x%02x%02x%02x", |
|||
u[ 0], u[ 1], u[ 2], u[ 3], u[ 4], u[ 5], u[ 6], |
|||
u[ 7], u[ 8], u[ 9], u[10], u[11], u[12], u[13], |
|||
u[14], u[15]); |
|||
} |
|||
else { |
|||
return -EMSGSIZE; |
|||
} |
|||
} |
|||
|
|||
/***********************************************************************
|
|||
Store Galera checkpoint info in the 'xtrabackup_galera_info' file, if that |
|||
information is present in the trx system header. Otherwise, do nothing. */ |
|||
void |
|||
xb_write_galera_info(bool incremental_prepare) |
|||
/*==================*/ |
|||
{ |
|||
FILE* fp; |
|||
XID xid; |
|||
char uuid_str[40]; |
|||
wsrep_seqno_t seqno; |
|||
MY_STAT statinfo; |
|||
|
|||
/* Do not overwrite existing an existing file to be compatible with
|
|||
servers with older server versions */ |
|||
if (!incremental_prepare && |
|||
my_stat(XB_GALERA_INFO_FILENAME, &statinfo, MYF(0)) != NULL) { |
|||
|
|||
return; |
|||
} |
|||
|
|||
memset(&xid, 0, sizeof(xid)); |
|||
xid.formatID = -1; |
|||
|
|||
if (!trx_sys_read_wsrep_checkpoint(&xid)) { |
|||
|
|||
return; |
|||
} |
|||
|
|||
if (wsrep_uuid_print(wsrep_xid_uuid(&xid), uuid_str, |
|||
sizeof(uuid_str)) < 0) { |
|||
return; |
|||
} |
|||
|
|||
fp = fopen(XB_GALERA_INFO_FILENAME, "w"); |
|||
if (fp == NULL) { |
|||
|
|||
msg("xtrabackup: error: " |
|||
"could not create " XB_GALERA_INFO_FILENAME |
|||
", errno = %d\n", |
|||
errno); |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
seqno = wsrep_xid_seqno(&xid); |
|||
|
|||
msg("xtrabackup: Recovered WSREP position: %s:%lld\n", |
|||
uuid_str, (long long) seqno); |
|||
|
|||
if (fprintf(fp, "%s:%lld", uuid_str, (long long) seqno) < 0) { |
|||
|
|||
msg("xtrabackup: error: " |
|||
"could not write to " XB_GALERA_INFO_FILENAME |
|||
", errno = %d\n", |
|||
errno); |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
fclose(fp); |
|||
} |
|||
#endif
|
@ -0,0 +1,32 @@ |
|||
/****************************************************** |
|||
Percona XtraBackup: hot backup tool for InnoDB |
|||
(c) 2009-2014 Percona LLC and/or its affiliates |
|||
Originally Created 3/3/2009 Yasufumi Kinoshita |
|||
Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko, |
|||
Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*******************************************************/ |
|||
|
|||
#ifndef WSREP_H |
|||
#define WSREP_H |
|||
|
|||
/*********************************************************************** |
|||
Store Galera checkpoint info in the 'xtrabackup_galera_info' file, if that |
|||
information is present in the trx system header. Otherwise, do nothing. */ |
|||
void |
|||
xb_write_galera_info(bool incremental_prepare); |
|||
/*==================*/ |
|||
|
|||
#endif |
@ -0,0 +1,78 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2012 Percona LLC and/or its affiliates. |
|||
|
|||
Declarations of XtraBackup functions called by InnoDB code. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef xb0xb_h |
|||
#define xb0xb_h |
|||
|
|||
|
|||
extern void os_io_init_simple(void); |
|||
extern os_file_t files[1000]; |
|||
extern const char *innodb_checksum_algorithm_names[]; |
|||
extern TYPELIB innodb_checksum_algorithm_typelib; |
|||
extern dberr_t open_or_create_data_files( |
|||
ibool* create_new_db, |
|||
#ifdef UNIV_LOG_ARCHIVE |
|||
lsn_t* min_arch_log_no, |
|||
lsn_t* max_arch_log_no, |
|||
#endif |
|||
lsn_t* min_flushed_lsn, |
|||
lsn_t* max_flushed_lsn, |
|||
ulint* sum_of_new_sizes) |
|||
; |
|||
int |
|||
fil_file_readdir_next_file( |
|||
/*=======================*/ |
|||
dberr_t* err, /*!< out: this is set to DB_ERROR if an error |
|||
was encountered, otherwise not changed */ |
|||
const char* dirname,/*!< in: directory name or path */ |
|||
os_file_dir_t dir, /*!< in: directory stream */ |
|||
os_file_stat_t* info) /*!< in/out: buffer where the |
|||
info is returned */; |
|||
buf_block_t* btr_node_ptr_get_child( |
|||
const rec_t* node_ptr,/*!< in: node pointer */ |
|||
dict_index_t* index, /*!< in: index */ |
|||
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */ |
|||
mtr_t* mtr) /*!< in: mtr */; |
|||
|
|||
buf_block_t* |
|||
btr_root_block_get( |
|||
/*===============*/ |
|||
const dict_index_t* index, /*!< in: index tree */ |
|||
ulint mode, /*!< in: either RW_S_LATCH |
|||
or RW_X_LATCH */ |
|||
mtr_t* mtr) /*!< in: mtr */; |
|||
fil_space_t* |
|||
fil_space_get_by_name(const char *); |
|||
ibool |
|||
recv_check_cp_is_consistent(const byte* buf); |
|||
void |
|||
innodb_log_checksum_func_update( |
|||
/*============================*/ |
|||
ulint algorithm) /*!< in: algorithm */; |
|||
dberr_t recv_find_max_checkpoint(log_group_t** max_group, ulint* max_field); |
|||
dberr_t |
|||
srv_undo_tablespaces_init( |
|||
/*======================*/ |
|||
ibool create_new_db, |
|||
ibool backup_mode, |
|||
const ulint n_conf_tablespaces, |
|||
ulint* n_opened); |
|||
|
|||
#endif |
@ -0,0 +1,48 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2011-2013 Percona LLC and/or its affiliates. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
/* This file is required to abstract away regex(3) calls so that |
|||
my_regex is used on Windows and native calls are used on POSIX platforms. */ |
|||
|
|||
#ifndef XB_REGEX_H |
|||
#define XB_REGEX_H |
|||
|
|||
#ifdef HAVE_SYSTEM_REGEX |
|||
#include <regex.h> |
|||
#else |
|||
#include <pcreposix.h> |
|||
#endif |
|||
|
|||
typedef regex_t* xb_regex_t; |
|||
|
|||
#define xb_regex_init() |
|||
|
|||
#define xb_regexec(preg,string,nmatch,pmatch,eflags) \ |
|||
regexec(preg, string, nmatch, pmatch, eflags) |
|||
|
|||
#define xb_regerror(errcode,preg,errbuf,errbuf_size) \ |
|||
regerror(errcode, preg, errbuf, errbuf_size) |
|||
|
|||
#define xb_regcomp(preg,regex,cflags) \ |
|||
regcomp(preg, regex, cflags) |
|||
|
|||
#define xb_regfree(preg) regfree(preg) |
|||
|
|||
#define xb_regex_end() |
|||
|
|||
#endif /* XB_REGEX_H */ |
2721
extra/mariabackup/xbcloud.cc
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,696 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2013 Percona LLC and/or its affiliates. |
|||
|
|||
The xbcrypt utility: decrypt files in the XBCRYPT format. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include <my_base.h> |
|||
#include <my_getopt.h> |
|||
#include "common.h" |
|||
#include "xbcrypt.h" |
|||
#include "xbcrypt_common.h" |
|||
#include "crc_glue.h" |
|||
|
|||
#if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600) |
|||
GCRY_THREAD_OPTION_PTHREAD_IMPL; |
|||
#endif |
|||
|
|||
#define XBCRYPT_VERSION "1.1" |
|||
|
|||
typedef enum { |
|||
RUN_MODE_NONE, |
|||
RUN_MODE_ENCRYPT, |
|||
RUN_MODE_DECRYPT |
|||
} run_mode_t; |
|||
|
|||
const char *xbcrypt_encrypt_algo_names[] = |
|||
{ "NONE", "AES128", "AES192", "AES256", NullS}; |
|||
TYPELIB xbcrypt_encrypt_algo_typelib= |
|||
{array_elements(xbcrypt_encrypt_algo_names)-1,"", |
|||
xbcrypt_encrypt_algo_names, NULL}; |
|||
|
|||
static run_mode_t opt_run_mode = RUN_MODE_ENCRYPT; |
|||
static char *opt_input_file = NULL; |
|||
static char *opt_output_file = NULL; |
|||
static ulong opt_encrypt_algo; |
|||
static char *opt_encrypt_key_file = NULL; |
|||
static void *opt_encrypt_key = NULL; |
|||
static ulonglong opt_encrypt_chunk_size = 0; |
|||
static my_bool opt_verbose = FALSE; |
|||
|
|||
static uint encrypt_algos[] = { GCRY_CIPHER_NONE, |
|||
GCRY_CIPHER_AES128, |
|||
GCRY_CIPHER_AES192, |
|||
GCRY_CIPHER_AES256 }; |
|||
static int encrypt_algo = 0; |
|||
static int encrypt_mode = GCRY_CIPHER_MODE_CTR; |
|||
static uint encrypt_key_len = 0; |
|||
static size_t encrypt_iv_len = 0; |
|||
|
|||
static struct my_option my_long_options[] = |
|||
{ |
|||
{"help", '?', "Display this help and exit.", |
|||
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
|||
|
|||
{"decrypt", 'd', "Decrypt data input to output.", |
|||
0, 0, 0, |
|||
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
|||
|
|||
{"input", 'i', "Optional input file. If not specified, input" |
|||
" will be read from standard input.", |
|||
&opt_input_file, &opt_input_file, 0, |
|||
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|||
|
|||
{"output", 'o', "Optional output file. If not specified, output" |
|||
" will be written to standard output.", |
|||
&opt_output_file, &opt_output_file, 0, |
|||
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|||
|
|||
{"encrypt-algo", 'a', "Encryption algorithm.", |
|||
&opt_encrypt_algo, &opt_encrypt_algo, &xbcrypt_encrypt_algo_typelib, |
|||
GET_ENUM, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|||
|
|||
{"encrypt-key", 'k', "Encryption key.", |
|||
&opt_encrypt_key, &opt_encrypt_key, 0, |
|||
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|||
|
|||
{"encrypt-key-file", 'f', "File which contains encryption key.", |
|||
&opt_encrypt_key_file, &opt_encrypt_key_file, 0, |
|||
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|||
|
|||
{"encrypt-chunk-size", 's', "Size of working buffer for encryption in" |
|||
" bytes. The default value is 64K.", |
|||
&opt_encrypt_chunk_size, &opt_encrypt_chunk_size, 0, |
|||
GET_ULL, REQUIRED_ARG, (1 << 16), 1024, ULONGLONG_MAX, 0, 0, 0}, |
|||
|
|||
{"verbose", 'v', "Display verbose status output.", |
|||
&opt_verbose, &opt_verbose, |
|||
0, GET_BOOL, 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 |
|||
int |
|||
get_options(int *argc, char ***argv); |
|||
|
|||
static |
|||
my_bool |
|||
get_one_option(int optid, const struct my_option *opt __attribute__((unused)), |
|||
char *argument __attribute__((unused))); |
|||
|
|||
static |
|||
void |
|||
print_version(void); |
|||
|
|||
static |
|||
void |
|||
usage(void); |
|||
|
|||
static |
|||
int |
|||
mode_decrypt(File filein, File fileout); |
|||
|
|||
static |
|||
int |
|||
mode_encrypt(File filein, File fileout); |
|||
|
|||
int |
|||
main(int argc, char **argv) |
|||
{ |
|||
#if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600) |
|||
gcry_error_t gcry_error; |
|||
#endif |
|||
File filein = 0; |
|||
File fileout = 0; |
|||
|
|||
MY_INIT(argv[0]); |
|||
|
|||
crc_init(); |
|||
|
|||
if (get_options(&argc, &argv)) { |
|||
goto err; |
|||
} |
|||
|
|||
/* Acording to gcrypt docs (and my testing), setting up the threading |
|||
callbacks must be done first, so, lets give it a shot */ |
|||
#if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600) |
|||
gcry_error = gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); |
|||
if (gcry_error) { |
|||
msg("%s: unable to set libgcrypt thread cbs - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return 1; |
|||
} |
|||
#endif |
|||
|
|||
/* Version check should be the very first call because it |
|||
makes sure that important subsystems are intialized. */ |
|||
if (!gcry_control(GCRYCTL_ANY_INITIALIZATION_P)) { |
|||
const char *gcrypt_version; |
|||
gcrypt_version = gcry_check_version(NULL); |
|||
/* No other library has already initialized libgcrypt. */ |
|||
if (!gcrypt_version) { |
|||
msg("%s: failed to initialize libgcrypt\n", |
|||
my_progname); |
|||
return 1; |
|||
} else if (opt_verbose) { |
|||
msg("%s: using gcrypt %s\n", my_progname, |
|||
gcrypt_version); |
|||
} |
|||
} |
|||
gcry_control(GCRYCTL_DISABLE_SECMEM, 0); |
|||
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); |
|||
|
|||
/* Determine the algorithm */ |
|||
encrypt_algo = encrypt_algos[opt_encrypt_algo]; |
|||
|
|||
/* Set up the iv length */ |
|||
encrypt_iv_len = gcry_cipher_get_algo_blklen(encrypt_algo); |
|||
|
|||
/* Now set up the key */ |
|||
if (opt_encrypt_key == NULL && opt_encrypt_key_file == NULL) { |
|||
msg("%s: no encryption key or key file specified.\n", |
|||
my_progname); |
|||
return 1; |
|||
} else if (opt_encrypt_key && opt_encrypt_key_file) { |
|||
msg("%s: both encryption key and key file specified.\n", |
|||
my_progname); |
|||
return 1; |
|||
} else if (opt_encrypt_key_file) { |
|||
if (!xb_crypt_read_key_file(opt_encrypt_key_file, |
|||
&opt_encrypt_key, |
|||
&encrypt_key_len)) { |
|||
msg("%s: unable to read encryption key file \"%s\".\n", |
|||
opt_encrypt_key_file, my_progname); |
|||
return 1; |
|||
} |
|||
} else { |
|||
encrypt_key_len = strlen(opt_encrypt_key); |
|||
} |
|||
|
|||
if (opt_input_file) { |
|||
MY_STAT mystat; |
|||
|
|||
if (opt_verbose) |
|||
msg("%s: input file \"%s\".\n", my_progname, |
|||
opt_input_file); |
|||
|
|||
if (my_stat(opt_input_file, &mystat, MYF(MY_WME)) == NULL) { |
|||
goto err; |
|||
} |
|||
if (!MY_S_ISREG(mystat.st_mode)) { |
|||
msg("%s: \"%s\" is not a regular file, exiting.\n", |
|||
my_progname, opt_input_file); |
|||
goto err; |
|||
} |
|||
if ((filein = my_open(opt_input_file, O_RDONLY, MYF(MY_WME))) |
|||
< 0) { |
|||
msg("%s: failed to open \"%s\".\n", my_progname, |
|||
opt_input_file); |
|||
goto err; |
|||
} |
|||
} else { |
|||
if (opt_verbose) |
|||
msg("%s: input from standard input.\n", my_progname); |
|||
filein = fileno(stdin); |
|||
} |
|||
|
|||
if (opt_output_file) { |
|||
if (opt_verbose) |
|||
msg("%s: output file \"%s\".\n", my_progname, |
|||
opt_output_file); |
|||
|
|||
if ((fileout = my_create(opt_output_file, 0, |
|||
O_WRONLY|O_BINARY|O_EXCL|O_NOFOLLOW, |
|||
MYF(MY_WME))) < 0) { |
|||
msg("%s: failed to create output file \"%s\".\n", |
|||
my_progname, opt_output_file); |
|||
goto err; |
|||
} |
|||
} else { |
|||
if (opt_verbose) |
|||
msg("%s: output to standard output.\n", my_progname); |
|||
fileout = fileno(stdout); |
|||
} |
|||
|
|||
if (opt_run_mode == RUN_MODE_DECRYPT |
|||
&& mode_decrypt(filein, fileout)) { |
|||
goto err; |
|||
} else if (opt_run_mode == RUN_MODE_ENCRYPT |
|||
&& mode_encrypt(filein, fileout)) { |
|||
goto err; |
|||
} |
|||
|
|||
if (opt_input_file && filein) { |
|||
my_close(filein, MYF(MY_WME)); |
|||
} |
|||
if (opt_output_file && fileout) { |
|||
my_close(fileout, MYF(MY_WME)); |
|||
} |
|||
|
|||
my_cleanup_options(my_long_options); |
|||
|
|||
my_end(0); |
|||
|
|||
return EXIT_SUCCESS; |
|||
err: |
|||
if (opt_input_file && filein) { |
|||
my_close(filein, MYF(MY_WME)); |
|||
} |
|||
if (opt_output_file && fileout) { |
|||
my_close(fileout, MYF(MY_WME)); |
|||
} |
|||
|
|||
my_cleanup_options(my_long_options); |
|||
|
|||
my_end(0); |
|||
|
|||
exit(EXIT_FAILURE); |
|||
|
|||
} |
|||
|
|||
|
|||
static |
|||
size_t |
|||
my_xb_crypt_read_callback(void *userdata, void *buf, size_t len) |
|||
{ |
|||
File* file = (File *) userdata; |
|||
return xb_read_full(*file, buf, len); |
|||
} |
|||
|
|||
static |
|||
int |
|||
mode_decrypt(File filein, File fileout) |
|||
{ |
|||
xb_rcrypt_t *xbcrypt_file = NULL; |
|||
void *chunkbuf = NULL; |
|||
size_t chunksize; |
|||
size_t originalsize; |
|||
void *ivbuf = NULL; |
|||
size_t ivsize; |
|||
void *decryptbuf = NULL; |
|||
size_t decryptbufsize = 0; |
|||
ulonglong ttlchunksread = 0; |
|||
ulonglong ttlbytesread = 0; |
|||
xb_rcrypt_result_t result; |
|||
gcry_cipher_hd_t cipher_handle; |
|||
gcry_error_t gcry_error; |
|||
my_bool hash_appended; |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) { |
|||
gcry_error = gcry_cipher_open(&cipher_handle, |
|||
encrypt_algo, |
|||
encrypt_mode, 0); |
|||
if (gcry_error) { |
|||
msg("%s:decrypt: unable to open libgcrypt" |
|||
" cipher - %s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return 1; |
|||
} |
|||
|
|||
gcry_error = gcry_cipher_setkey(cipher_handle, |
|||
opt_encrypt_key, |
|||
encrypt_key_len); |
|||
if (gcry_error) { |
|||
msg("%s:decrypt: unable to set libgcrypt cipher" |
|||
"key - %s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
goto err; |
|||
} |
|||
} |
|||
|
|||
/* Initialize the xb_crypt format reader */ |
|||
xbcrypt_file = xb_crypt_read_open(&filein, my_xb_crypt_read_callback); |
|||
if (xbcrypt_file == NULL) { |
|||
msg("%s:decrypt: xb_crypt_read_open() failed.\n", my_progname); |
|||
goto err; |
|||
} |
|||
|
|||
/* Walk the encrypted chunks, decrypting them and writing out */ |
|||
while ((result = xb_crypt_read_chunk(xbcrypt_file, &chunkbuf, |
|||
&originalsize, &chunksize, |
|||
&ivbuf, &ivsize, &hash_appended)) |
|||
== XB_CRYPT_READ_CHUNK) { |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) { |
|||
gcry_error = gcry_cipher_reset(cipher_handle); |
|||
if (gcry_error) { |
|||
msg("%s:decrypt: unable to reset libgcrypt" |
|||
" cipher - %s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
goto err; |
|||
} |
|||
|
|||
if (ivsize) { |
|||
gcry_error = gcry_cipher_setctr(cipher_handle, |
|||
ivbuf, |
|||
ivsize); |
|||
} |
|||
if (gcry_error) { |
|||
msg("%s:decrypt: unable to set cipher iv - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
continue; |
|||
} |
|||
|
|||
if (decryptbufsize < originalsize) { |
|||
decryptbuf = my_realloc(decryptbuf, |
|||
originalsize, |
|||
MYF(MY_WME | MY_ALLOW_ZERO_PTR)); |
|||
decryptbufsize = originalsize; |
|||
} |
|||
|
|||
/* Try to decrypt it */ |
|||
gcry_error = gcry_cipher_decrypt(cipher_handle, |
|||
decryptbuf, |
|||
originalsize, |
|||
chunkbuf, |
|||
chunksize); |
|||
if (gcry_error) { |
|||
msg("%s:decrypt: unable to decrypt chunk - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
gcry_cipher_close(cipher_handle); |
|||
goto err; |
|||
} |
|||
|
|||
} else { |
|||
decryptbuf = chunkbuf; |
|||
} |
|||
|
|||
if (hash_appended) { |
|||
uchar hash[XB_CRYPT_HASH_LEN]; |
|||
|
|||
originalsize -= XB_CRYPT_HASH_LEN; |
|||
|
|||
/* ensure that XB_CRYPT_HASH_LEN is the correct length |
|||
of XB_CRYPT_HASH hashing algorithm output */ |
|||
xb_a(gcry_md_get_algo_dlen(XB_CRYPT_HASH) == |
|||
XB_CRYPT_HASH_LEN); |
|||
gcry_md_hash_buffer(XB_CRYPT_HASH, hash, decryptbuf, |
|||
originalsize); |
|||
if (memcmp(hash, (char *) decryptbuf + originalsize, |
|||
XB_CRYPT_HASH_LEN) != 0) { |
|||
msg("%s:%s invalid plaintext hash. " |
|||
"Wrong encrytion key specified?\n", |
|||
my_progname, __FUNCTION__); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
} |
|||
|
|||
/* Write it out */ |
|||
if (my_write(fileout, (const uchar *) decryptbuf, originalsize, |
|||
MYF(MY_WME | MY_NABP))) { |
|||
msg("%s:decrypt: unable to write output chunk.\n", |
|||
my_progname); |
|||
goto err; |
|||
} |
|||
ttlchunksread++; |
|||
ttlbytesread += chunksize; |
|||
if (opt_verbose) |
|||
msg("%s:decrypt: %llu chunks read, %llu bytes read\n.", |
|||
my_progname, ttlchunksread, ttlbytesread); |
|||
} |
|||
|
|||
xb_crypt_read_close(xbcrypt_file); |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) |
|||
gcry_cipher_close(cipher_handle); |
|||
|
|||
if (decryptbuf && decryptbufsize) |
|||
my_free(decryptbuf); |
|||
|
|||
if (opt_verbose) |
|||
msg("\n%s:decrypt: done\n", my_progname); |
|||
|
|||
return 0; |
|||
err: |
|||
if (xbcrypt_file) |
|||
xb_crypt_read_close(xbcrypt_file); |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) |
|||
gcry_cipher_close(cipher_handle); |
|||
|
|||
if (decryptbuf && decryptbufsize) |
|||
my_free(decryptbuf); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
static |
|||
ssize_t |
|||
my_xb_crypt_write_callback(void *userdata, const void *buf, size_t len) |
|||
{ |
|||
File* file = (File *) userdata; |
|||
|
|||
ssize_t ret = my_write(*file, buf, len, MYF(MY_WME)); |
|||
posix_fadvise(*file, 0, 0, POSIX_FADV_DONTNEED); |
|||
return ret; |
|||
} |
|||
|
|||
static |
|||
int |
|||
mode_encrypt(File filein, File fileout) |
|||
{ |
|||
size_t bytesread; |
|||
size_t chunkbuflen; |
|||
uchar *chunkbuf = NULL; |
|||
void *ivbuf = NULL; |
|||
size_t encryptbuflen = 0; |
|||
size_t encryptedlen = 0; |
|||
void *encryptbuf = NULL; |
|||
ulonglong ttlchunkswritten = 0; |
|||
ulonglong ttlbyteswritten = 0; |
|||
xb_wcrypt_t *xbcrypt_file = NULL; |
|||
gcry_cipher_hd_t cipher_handle; |
|||
gcry_error_t gcry_error; |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) { |
|||
gcry_error = gcry_cipher_open(&cipher_handle, |
|||
encrypt_algo, |
|||
encrypt_mode, 0); |
|||
if (gcry_error) { |
|||
msg("%s:encrypt: unable to open libgcrypt cipher - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return 1; |
|||
} |
|||
|
|||
gcry_error = gcry_cipher_setkey(cipher_handle, |
|||
opt_encrypt_key, |
|||
encrypt_key_len); |
|||
if (gcry_error) { |
|||
msg("%s:encrypt: unable to set libgcrypt cipher key - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
goto err; |
|||
} |
|||
} |
|||
|
|||
posix_fadvise(filein, 0, 0, POSIX_FADV_SEQUENTIAL); |
|||
|
|||
xbcrypt_file = xb_crypt_write_open(&fileout, |
|||
my_xb_crypt_write_callback); |
|||
if (xbcrypt_file == NULL) { |
|||
msg("%s:encrypt: xb_crypt_write_open() failed.\n", |
|||
my_progname); |
|||
goto err; |
|||
} |
|||
|
|||
ivbuf = my_malloc(encrypt_iv_len, MYF(MY_FAE)); |
|||
|
|||
/* now read in data in chunk size, encrypt and write out */ |
|||
chunkbuflen = opt_encrypt_chunk_size + XB_CRYPT_HASH_LEN; |
|||
chunkbuf = (uchar *) my_malloc(chunkbuflen, MYF(MY_FAE)); |
|||
while ((bytesread = my_read(filein, chunkbuf, opt_encrypt_chunk_size, |
|||
MYF(MY_WME))) > 0) { |
|||
|
|||
size_t origbuflen = bytesread + XB_CRYPT_HASH_LEN; |
|||
|
|||
/* ensure that XB_CRYPT_HASH_LEN is the correct length |
|||
of XB_CRYPT_HASH hashing algorithm output */ |
|||
xb_a(XB_CRYPT_HASH_LEN == gcry_md_get_algo_dlen(XB_CRYPT_HASH)); |
|||
gcry_md_hash_buffer(XB_CRYPT_HASH, chunkbuf + bytesread, |
|||
chunkbuf, bytesread); |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) { |
|||
gcry_error = gcry_cipher_reset(cipher_handle); |
|||
|
|||
if (gcry_error) { |
|||
msg("%s:encrypt: unable to reset cipher - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
goto err; |
|||
} |
|||
|
|||
xb_crypt_create_iv(ivbuf, encrypt_iv_len); |
|||
gcry_error = gcry_cipher_setctr(cipher_handle, |
|||
ivbuf, |
|||
encrypt_iv_len); |
|||
|
|||
if (gcry_error) { |
|||
msg("%s:encrypt: unable to set cipher iv - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
continue; |
|||
} |
|||
|
|||
if (encryptbuflen < origbuflen) { |
|||
encryptbuf = my_realloc(encryptbuf, origbuflen, |
|||
MYF(MY_WME | MY_ALLOW_ZERO_PTR)); |
|||
encryptbuflen = origbuflen; |
|||
} |
|||
|
|||
gcry_error = gcry_cipher_encrypt(cipher_handle, |
|||
encryptbuf, |
|||
encryptbuflen, |
|||
chunkbuf, |
|||
origbuflen); |
|||
|
|||
encryptedlen = origbuflen; |
|||
|
|||
if (gcry_error) { |
|||
msg("%s:encrypt: unable to encrypt chunk - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
gcry_cipher_close(cipher_handle); |
|||
goto err; |
|||
} |
|||
} else { |
|||
encryptedlen = origbuflen; |
|||
encryptbuf = chunkbuf; |
|||
} |
|||
|
|||
if (xb_crypt_write_chunk(xbcrypt_file, encryptbuf, |
|||
bytesread + XB_CRYPT_HASH_LEN, |
|||
encryptedlen, ivbuf, encrypt_iv_len)) { |
|||
msg("%s:encrypt: abcrypt_write_chunk() failed.\n", |
|||
my_progname); |
|||
goto err; |
|||
} |
|||
|
|||
ttlchunkswritten++; |
|||
ttlbyteswritten += encryptedlen; |
|||
|
|||
if (opt_verbose) |
|||
msg("%s:encrypt: %llu chunks written, %llu bytes " |
|||
"written\n.", my_progname, ttlchunkswritten, |
|||
ttlbyteswritten); |
|||
} |
|||
|
|||
my_free(ivbuf); |
|||
my_free(chunkbuf); |
|||
|
|||
if (encryptbuf && encryptbuflen) |
|||
my_free(encryptbuf); |
|||
|
|||
xb_crypt_write_close(xbcrypt_file); |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) |
|||
gcry_cipher_close(cipher_handle); |
|||
|
|||
if (opt_verbose) |
|||
msg("\n%s:encrypt: done\n", my_progname); |
|||
|
|||
return 0; |
|||
err: |
|||
if (chunkbuf) |
|||
my_free(chunkbuf); |
|||
|
|||
if (encryptbuf && encryptbuflen) |
|||
my_free(encryptbuf); |
|||
|
|||
if (xbcrypt_file) |
|||
xb_crypt_write_close(xbcrypt_file); |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) |
|||
gcry_cipher_close(cipher_handle); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
static |
|||
int |
|||
get_options(int *argc, char ***argv) |
|||
{ |
|||
int ho_error; |
|||
|
|||
if ((ho_error= handle_options(argc, argv, my_long_options, |
|||
get_one_option))) { |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static |
|||
my_bool |
|||
get_one_option(int optid, const struct my_option *opt __attribute__((unused)), |
|||
char *argument __attribute__((unused))) |
|||
{ |
|||
switch (optid) { |
|||
case 'd': |
|||
opt_run_mode = RUN_MODE_DECRYPT; |
|||
break; |
|||
case '?': |
|||
usage(); |
|||
exit(0); |
|||
} |
|||
|
|||
return FALSE; |
|||
} |
|||
|
|||
static |
|||
void |
|||
print_version(void) |
|||
{ |
|||
printf("%s Ver %s for %s (%s)\n", my_progname, XBCRYPT_VERSION, |
|||
SYSTEM_TYPE, MACHINE_TYPE); |
|||
} |
|||
|
|||
static |
|||
void |
|||
usage(void) |
|||
{ |
|||
print_version(); |
|||
puts("Copyright (C) 2011 Percona Inc."); |
|||
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("Encrypt or decrypt files in the XBCRYPT format.\n"); |
|||
|
|||
puts("Usage: "); |
|||
printf(" %s [OPTIONS...]" |
|||
" # read data from specified input, encrypting or decrypting " |
|||
" and writing the result to the specified output.\n", |
|||
my_progname); |
|||
puts("\nOptions:"); |
|||
my_print_help(my_long_options); |
|||
} |
@ -0,0 +1,79 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2011 Percona LLC and/or its affiliates. |
|||
|
|||
Encryption interface for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef XBCRYPT_H |
|||
#define XBCRYPT_H |
|||
|
|||
#include <my_base.h> |
|||
#include "common.h" |
|||
|
|||
#define XB_CRYPT_CHUNK_MAGIC1 "XBCRYP01" |
|||
#define XB_CRYPT_CHUNK_MAGIC2 "XBCRYP02" |
|||
#define XB_CRYPT_CHUNK_MAGIC3 "XBCRYP03" /* must be same size as ^^ */ |
|||
#define XB_CRYPT_CHUNK_MAGIC_CURRENT XB_CRYPT_CHUNK_MAGIC3 |
|||
#define XB_CRYPT_CHUNK_MAGIC_SIZE (sizeof(XB_CRYPT_CHUNK_MAGIC1)-1) |
|||
|
|||
#define XB_CRYPT_HASH GCRY_MD_SHA256 |
|||
#define XB_CRYPT_HASH_LEN 32 |
|||
|
|||
/****************************************************************************** |
|||
Write interface */ |
|||
typedef struct xb_wcrypt_struct xb_wcrypt_t; |
|||
|
|||
/* Callback on write for i/o, must return # of bytes written or -1 on error */ |
|||
typedef ssize_t xb_crypt_write_callback(void *userdata, |
|||
const void *buf, size_t len); |
|||
|
|||
xb_wcrypt_t *xb_crypt_write_open(void *userdata, |
|||
xb_crypt_write_callback *onwrite); |
|||
|
|||
/* Takes buffer, original length, encrypted length iv and iv length, formats |
|||
output buffer and calls write callback. |
|||
Returns 0 on success, 1 on error */ |
|||
int xb_crypt_write_chunk(xb_wcrypt_t *crypt, const void *buf, size_t olen, |
|||
size_t elen, const void *iv, size_t ivlen); |
|||
|
|||
/* Returns 0 on success, 1 on error */ |
|||
int xb_crypt_write_close(xb_wcrypt_t *crypt); |
|||
|
|||
/****************************************************************************** |
|||
Read interface */ |
|||
typedef struct xb_rcrypt_struct xb_rcrypt_t; |
|||
|
|||
/* Callback on read for i/o, must return # of bytes read or -1 on error */ |
|||
typedef size_t xb_crypt_read_callback(void *userdata, void *buf, size_t len); |
|||
|
|||
xb_rcrypt_t *xb_crypt_read_open(void *userdata, |
|||
xb_crypt_read_callback *onread); |
|||
|
|||
typedef enum { |
|||
XB_CRYPT_READ_CHUNK, |
|||
XB_CRYPT_READ_INCOMPLETE, |
|||
XB_CRYPT_READ_EOF, |
|||
XB_CRYPT_READ_ERROR |
|||
} xb_rcrypt_result_t; |
|||
|
|||
xb_rcrypt_result_t xb_crypt_read_chunk(xb_rcrypt_t *crypt, void **buf, |
|||
size_t *olen, size_t *elen, void **iv, |
|||
size_t *ivlen, my_bool *hash_appended); |
|||
|
|||
int xb_crypt_read_close(xb_rcrypt_t *crypt); |
|||
|
|||
#endif |
@ -0,0 +1,328 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2013, 2017 Percona LLC and/or its affiliates. |
|||
|
|||
Encryption configuration file interface for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include <my_base.h> |
|||
#include "common.h" |
|||
#include "xbcrypt.h" |
|||
#include "xbcrypt_common.h" |
|||
|
|||
/* Encryption options */ |
|||
char *ds_encrypt_key = NULL; |
|||
char *ds_encrypt_key_file = NULL; |
|||
ulong ds_encrypt_algo; |
|||
|
|||
static uint encrypt_key_len; |
|||
static uint encrypt_iv_len; |
|||
|
|||
static const uint encrypt_mode = GCRY_CIPHER_MODE_CTR; |
|||
|
|||
static uint encrypt_algos[] = { GCRY_CIPHER_NONE, GCRY_CIPHER_AES128, |
|||
GCRY_CIPHER_AES192, GCRY_CIPHER_AES256 }; |
|||
static uint encrypt_algo; |
|||
|
|||
#if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600) |
|||
GCRY_THREAD_OPTION_PTHREAD_IMPL; |
|||
#endif |
|||
|
|||
|
|||
my_bool |
|||
xb_crypt_read_key_file(const char *filename, void** key, uint *keylength) |
|||
{ |
|||
FILE *fp; |
|||
|
|||
if (!(fp = my_fopen(filename, O_RDONLY, MYF(0)))) { |
|||
msg("%s:%s: unable to open config file \"%s\", errno(%d)\n", |
|||
my_progname, __FUNCTION__, filename, my_errno); |
|||
return FALSE; |
|||
} |
|||
|
|||
fseek(fp, 0 , SEEK_END); |
|||
*keylength = ftell(fp); |
|||
rewind(fp); |
|||
*key = my_malloc(*keylength, MYF(MY_FAE)); |
|||
*keylength = fread(*key, 1, *keylength, fp); |
|||
my_fclose(fp, MYF(0)); |
|||
return TRUE; |
|||
} |
|||
|
|||
void |
|||
xb_crypt_create_iv(void* ivbuf, size_t ivlen) |
|||
{ |
|||
gcry_create_nonce(ivbuf, ivlen); |
|||
} |
|||
|
|||
gcry_error_t |
|||
xb_crypt_init(uint *iv_len) |
|||
{ |
|||
gcry_error_t gcry_error; |
|||
|
|||
/* Acording to gcrypt docs (and my testing), setting up the threading |
|||
callbacks must be done first, so, lets give it a shot */ |
|||
#if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600) |
|||
gcry_error = gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); |
|||
if (gcry_error) { |
|||
msg("encryption: unable to set libgcrypt thread cbs - " |
|||
"%s : %s\n", |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return gcry_error; |
|||
} |
|||
#endif |
|||
|
|||
/* Version check should be the very next call because it |
|||
makes sure that important subsystems are intialized. */ |
|||
if (!gcry_control(GCRYCTL_ANY_INITIALIZATION_P)) { |
|||
const char *gcrypt_version; |
|||
gcrypt_version = gcry_check_version(NULL); |
|||
/* No other library has already initialized libgcrypt. */ |
|||
if (!gcrypt_version) { |
|||
msg("encryption: failed to initialize libgcrypt\n"); |
|||
return 1; |
|||
} else { |
|||
msg("encryption: using gcrypt %s\n", gcrypt_version); |
|||
} |
|||
} |
|||
|
|||
/* Disable the gcry secure memory, not dealing with this for now */ |
|||
gcry_error = gcry_control(GCRYCTL_DISABLE_SECMEM, 0); |
|||
if (gcry_error) { |
|||
msg("encryption: unable to disable libgcrypt secmem - " |
|||
"%s : %s\n", |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return gcry_error; |
|||
} |
|||
|
|||
/* Finalize gcry initialization. */ |
|||
gcry_error = gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); |
|||
if (gcry_error) { |
|||
msg("encryption: unable to finish libgcrypt initialization - " |
|||
"%s : %s\n", |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return gcry_error; |
|||
} |
|||
|
|||
/* Determine the algorithm */ |
|||
encrypt_algo = encrypt_algos[ds_encrypt_algo]; |
|||
|
|||
/* Set up the iv length */ |
|||
encrypt_iv_len = gcry_cipher_get_algo_blklen(encrypt_algo); |
|||
xb_a(encrypt_iv_len > 0); |
|||
if (iv_len != NULL) { |
|||
*iv_len = encrypt_iv_len; |
|||
} |
|||
|
|||
/* Now set up the key */ |
|||
if (ds_encrypt_key == NULL && |
|||
ds_encrypt_key_file == NULL) { |
|||
msg("encryption: no encryption key or key file specified.\n"); |
|||
return gcry_error; |
|||
} else if (ds_encrypt_key && ds_encrypt_key_file) { |
|||
msg("encryption: both encryption key and key file specified.\n"); |
|||
return gcry_error; |
|||
} else if (ds_encrypt_key_file) { |
|||
if (!xb_crypt_read_key_file(ds_encrypt_key_file, |
|||
(void**)&ds_encrypt_key, |
|||
&encrypt_key_len)) { |
|||
msg("encryption: unable to read encryption key file" |
|||
" \"%s\".\n", ds_encrypt_key_file); |
|||
return gcry_error; |
|||
} |
|||
} else if (ds_encrypt_key) { |
|||
encrypt_key_len = strlen(ds_encrypt_key); |
|||
} else { |
|||
msg("encryption: no encryption key or key file specified.\n"); |
|||
return gcry_error; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
gcry_error_t |
|||
xb_crypt_cipher_open(gcry_cipher_hd_t *cipher_handle) |
|||
{ |
|||
if (encrypt_algo != GCRY_CIPHER_NONE) { |
|||
gcry_error_t gcry_error; |
|||
|
|||
gcry_error = gcry_cipher_open(cipher_handle, |
|||
encrypt_algo, |
|||
encrypt_mode, 0); |
|||
if (gcry_error) { |
|||
msg("encryption: unable to open libgcrypt" |
|||
" cipher - %s : %s\n", |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
gcry_cipher_close(*cipher_handle); |
|||
return gcry_error; |
|||
} |
|||
|
|||
gcry_error = gcry_cipher_setkey(*cipher_handle, |
|||
ds_encrypt_key, |
|||
encrypt_key_len); |
|||
if (gcry_error) { |
|||
msg("encryption: unable to set libgcrypt" |
|||
" cipher key - %s : %s\n", |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
gcry_cipher_close(*cipher_handle); |
|||
return gcry_error; |
|||
} |
|||
return gcry_error; |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
void |
|||
xb_crypt_cipher_close(gcry_cipher_hd_t cipher_handle) |
|||
{ |
|||
if (encrypt_algo != GCRY_CIPHER_NONE) |
|||
gcry_cipher_close(cipher_handle); |
|||
} |
|||
|
|||
gcry_error_t |
|||
xb_crypt_decrypt(gcry_cipher_hd_t cipher_handle, const uchar *from, |
|||
size_t from_len, uchar *to, size_t *to_len, |
|||
const uchar *iv, size_t iv_len, my_bool hash_appended) |
|||
{ |
|||
*to_len = from_len; |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) { |
|||
|
|||
gcry_error_t gcry_error; |
|||
|
|||
gcry_error = gcry_cipher_reset(cipher_handle); |
|||
if (gcry_error) { |
|||
msg("%s:encryption: unable to reset libgcrypt" |
|||
" cipher - %s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return gcry_error; |
|||
} |
|||
|
|||
if (iv_len > 0) { |
|||
gcry_error = gcry_cipher_setctr(cipher_handle, |
|||
iv, iv_len); |
|||
} |
|||
if (gcry_error) { |
|||
msg("%s:encryption: unable to set cipher iv - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return gcry_error; |
|||
} |
|||
|
|||
/* Try to decrypt it */ |
|||
gcry_error = gcry_cipher_decrypt(cipher_handle, to, *to_len, |
|||
from, from_len); |
|||
if (gcry_error) { |
|||
msg("%s:encryption: unable to decrypt chunk - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
gcry_cipher_close(cipher_handle); |
|||
return gcry_error; |
|||
} |
|||
|
|||
if (hash_appended) { |
|||
uchar hash[XB_CRYPT_HASH_LEN]; |
|||
|
|||
*to_len -= XB_CRYPT_HASH_LEN; |
|||
|
|||
/* ensure that XB_CRYPT_HASH_LEN is the correct length |
|||
of XB_CRYPT_HASH hashing algorithm output */ |
|||
xb_ad(gcry_md_get_algo_dlen(XB_CRYPT_HASH) == |
|||
XB_CRYPT_HASH_LEN); |
|||
gcry_md_hash_buffer(XB_CRYPT_HASH, hash, to, |
|||
*to_len); |
|||
if (memcmp(hash, (char *) to + *to_len, |
|||
XB_CRYPT_HASH_LEN) != 0) { |
|||
msg("%s:%s invalid plaintext hash. " |
|||
"Wrong encrytion key specified?\n", |
|||
my_progname, __FUNCTION__); |
|||
return 1; |
|||
} |
|||
} |
|||
|
|||
} else { |
|||
memcpy(to, from, *to_len); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
gcry_error_t |
|||
xb_crypt_encrypt(gcry_cipher_hd_t cipher_handle, const uchar *from, |
|||
size_t from_len, uchar *to, size_t *to_len, uchar *iv) |
|||
{ |
|||
gcry_error_t gcry_error; |
|||
|
|||
/* ensure that XB_CRYPT_HASH_LEN is the correct length |
|||
of XB_CRYPT_HASH hashing algorithm output */ |
|||
xb_ad(gcry_md_get_algo_dlen(XB_CRYPT_HASH) == |
|||
XB_CRYPT_HASH_LEN); |
|||
|
|||
memcpy(to, from, from_len); |
|||
gcry_md_hash_buffer(XB_CRYPT_HASH, to + from_len, |
|||
from, from_len); |
|||
|
|||
*to_len = from_len; |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) { |
|||
|
|||
gcry_error = gcry_cipher_reset(cipher_handle); |
|||
if (gcry_error) { |
|||
msg("encrypt: unable to reset cipher - " |
|||
"%s : %s\n", |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return gcry_error; |
|||
} |
|||
|
|||
xb_crypt_create_iv(iv, encrypt_iv_len); |
|||
gcry_error = gcry_cipher_setctr(cipher_handle, iv, |
|||
encrypt_iv_len); |
|||
if (gcry_error) { |
|||
msg("encrypt: unable to set cipher ctr - " |
|||
"%s : %s\n", |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return gcry_error; |
|||
} |
|||
|
|||
gcry_error = gcry_cipher_encrypt(cipher_handle, to, |
|||
*to_len + XB_CRYPT_HASH_LEN, |
|||
to, |
|||
from_len + XB_CRYPT_HASH_LEN); |
|||
if (gcry_error) { |
|||
msg("encrypt: unable to encrypt buffer - " |
|||
"%s : %s\n", gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return gcry_error; |
|||
} |
|||
} else { |
|||
memcpy(to, from, from_len + XB_CRYPT_HASH_LEN); |
|||
} |
|||
|
|||
*to_len += XB_CRYPT_HASH_LEN; |
|||
|
|||
return 0; |
|||
} |
|||
#endif |
@ -0,0 +1,64 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2017 Percona LLC and/or its affiliates. |
|||
|
|||
Encryption datasink implementation for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include <my_base.h> |
|||
#if HAVE_GCRYPT |
|||
#if GCC_VERSION >= 4002 |
|||
/* Workaround to avoid "gcry_ac_* is deprecated" warnings in gcrypt.h */ |
|||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
|||
#endif |
|||
|
|||
#include <gcrypt.h> |
|||
|
|||
extern char *ds_encrypt_key; |
|||
extern char *ds_encrypt_key_file; |
|||
extern int ds_encrypt_threads; |
|||
extern ulong ds_encrypt_algo; |
|||
|
|||
/****************************************************************************** |
|||
Utility interface */ |
|||
my_bool xb_crypt_read_key_file(const char *filename, |
|||
void** key, uint *keylength); |
|||
|
|||
void xb_crypt_create_iv(void* ivbuf, size_t ivlen); |
|||
|
|||
/* Initialize gcrypt and setup encryption key and IV lengths */ |
|||
gcry_error_t |
|||
xb_crypt_init(uint *iv_len); |
|||
|
|||
/* Setup gcrypt cipher */ |
|||
gcry_error_t |
|||
xb_crypt_cipher_open(gcry_cipher_hd_t *cipher_handle); |
|||
|
|||
/* Close gcrypt cipher */ |
|||
void |
|||
xb_crypt_cipher_close(gcry_cipher_hd_t cipher_handle); |
|||
|
|||
/* Decrypt buffer */ |
|||
gcry_error_t |
|||
xb_crypt_decrypt(gcry_cipher_hd_t cipher_handle, const uchar *from, |
|||
size_t from_len, uchar *to, size_t *to_len, const uchar *iv, |
|||
size_t iv_len, my_bool hash_appended); |
|||
|
|||
/* Encrypt buffer */ |
|||
gcry_error_t |
|||
xb_crypt_encrypt(gcry_cipher_hd_t cipher_handle, const uchar *from, |
|||
size_t from_len, uchar *to, size_t *to_len, uchar *iv); |
|||
#endif |
@ -0,0 +1,252 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2013 Percona LLC and/or its affiliates. |
|||
|
|||
The xbcrypt format reader implementation. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include "xbcrypt.h" |
|||
#include "crc_glue.h" |
|||
|
|||
struct xb_rcrypt_struct { |
|||
void *userdata; |
|||
xb_crypt_read_callback *read; |
|||
void *buffer; |
|||
size_t bufsize; |
|||
void *ivbuffer; |
|||
size_t ivbufsize; |
|||
ulonglong offset; |
|||
}; |
|||
|
|||
xb_rcrypt_t * |
|||
xb_crypt_read_open(void *userdata, xb_crypt_read_callback *onread) |
|||
{ |
|||
xb_rcrypt_t *crypt; |
|||
|
|||
xb_ad(onread); |
|||
|
|||
crypt = (xb_rcrypt_t *) my_malloc(sizeof(xb_rcrypt_t), MYF(MY_FAE)); |
|||
|
|||
crypt->userdata = userdata; |
|||
crypt->read = onread; |
|||
crypt->buffer = NULL; |
|||
crypt->bufsize = 0; |
|||
crypt->offset = 0; |
|||
crypt->ivbuffer = NULL; |
|||
crypt->ivbufsize = 0; |
|||
return crypt; |
|||
} |
|||
|
|||
xb_rcrypt_result_t |
|||
xb_crypt_read_chunk(xb_rcrypt_t *crypt, void **buf, size_t *olen, size_t *elen, |
|||
void **iv, size_t *ivlen, my_bool *hash_appended) |
|||
|
|||
{ |
|||
uchar tmpbuf[XB_CRYPT_CHUNK_MAGIC_SIZE + 8 + 8 + 8 + 4]; |
|||
uchar *ptr; |
|||
ulonglong tmp; |
|||
ulong checksum, checksum_exp, version; |
|||
size_t bytesread; |
|||
xb_rcrypt_result_t result = XB_CRYPT_READ_CHUNK; |
|||
|
|||
if ((bytesread = crypt->read(crypt->userdata, tmpbuf, sizeof(tmpbuf))) |
|||
!= sizeof(tmpbuf)) { |
|||
if (bytesread == 0) { |
|||
result = XB_CRYPT_READ_EOF; |
|||
goto err; |
|||
} else { |
|||
msg("%s:%s: unable to read chunk header data at " |
|||
"offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, crypt->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
} |
|||
|
|||
ptr = tmpbuf; |
|||
|
|||
if (memcmp(ptr, XB_CRYPT_CHUNK_MAGIC3, |
|||
XB_CRYPT_CHUNK_MAGIC_SIZE) == 0) { |
|||
version = 3; |
|||
} else if (memcmp(ptr, XB_CRYPT_CHUNK_MAGIC2, |
|||
XB_CRYPT_CHUNK_MAGIC_SIZE) == 0) { |
|||
version = 2; |
|||
} else if (memcmp(ptr, XB_CRYPT_CHUNK_MAGIC1, |
|||
XB_CRYPT_CHUNK_MAGIC_SIZE) == 0) { |
|||
version = 1; |
|||
} else { |
|||
msg("%s:%s: wrong chunk magic at offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, crypt->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
|
|||
ptr += XB_CRYPT_CHUNK_MAGIC_SIZE; |
|||
crypt->offset += XB_CRYPT_CHUNK_MAGIC_SIZE; |
|||
|
|||
tmp = uint8korr(ptr); /* reserved */ |
|||
ptr += 8; |
|||
crypt->offset += 8; |
|||
|
|||
tmp = uint8korr(ptr); /* original size */ |
|||
ptr += 8; |
|||
if (tmp > INT_MAX) { |
|||
msg("%s:%s: invalid original size at offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, crypt->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
crypt->offset += 8; |
|||
*olen = (size_t)tmp; |
|||
|
|||
tmp = uint8korr(ptr); /* encrypted size */ |
|||
ptr += 8; |
|||
if (tmp > INT_MAX) { |
|||
msg("%s:%s: invalid encrypted size at offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, crypt->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
crypt->offset += 8; |
|||
*elen = (size_t)tmp; |
|||
|
|||
checksum_exp = uint4korr(ptr); /* checksum */ |
|||
ptr += 4; |
|||
crypt->offset += 4; |
|||
|
|||
/* iv size */ |
|||
if (version == 1) { |
|||
*ivlen = 0; |
|||
*iv = 0; |
|||
} else { |
|||
if ((bytesread = crypt->read(crypt->userdata, tmpbuf, 8)) |
|||
!= 8) { |
|||
if (bytesread == 0) { |
|||
result = XB_CRYPT_READ_EOF; |
|||
goto err; |
|||
} else { |
|||
msg("%s:%s: unable to read chunk iv size at " |
|||
"offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, crypt->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
} |
|||
|
|||
tmp = uint8korr(tmpbuf); |
|||
if (tmp > INT_MAX) { |
|||
msg("%s:%s: invalid iv size at offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, crypt->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
crypt->offset += 8; |
|||
*ivlen = (size_t)tmp; |
|||
} |
|||
|
|||
if (*ivlen > crypt->ivbufsize) { |
|||
crypt->ivbuffer = my_realloc(crypt->ivbuffer, *ivlen, |
|||
MYF(MY_WME | MY_ALLOW_ZERO_PTR)); |
|||
if (crypt->ivbuffer == NULL) { |
|||
msg("%s:%s: failed to increase iv buffer to " |
|||
"%llu bytes.\n", my_progname, __FUNCTION__, |
|||
(ulonglong)*ivlen); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
crypt->ivbufsize = *ivlen; |
|||
} |
|||
|
|||
if (*ivlen > 0) { |
|||
if (crypt->read(crypt->userdata, crypt->ivbuffer, *ivlen) |
|||
!= *ivlen) { |
|||
msg("%s:%s: failed to read %lld bytes for chunk iv " |
|||
"at offset 0x%llx.\n", my_progname, __FUNCTION__, |
|||
(ulonglong)*ivlen, crypt->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
*iv = crypt->ivbuffer; |
|||
} |
|||
|
|||
/* for version euqals 2 we need to read in the iv data but do not init |
|||
CTR with it */ |
|||
if (version == 2) { |
|||
*ivlen = 0; |
|||
*iv = 0; |
|||
} |
|||
|
|||
if (*olen > crypt->bufsize) { |
|||
crypt->buffer = my_realloc(crypt->buffer, *olen, |
|||
MYF(MY_WME | MY_ALLOW_ZERO_PTR)); |
|||
if (crypt->buffer == NULL) { |
|||
msg("%s:%s: failed to increase buffer to " |
|||
"%llu bytes.\n", my_progname, __FUNCTION__, |
|||
(ulonglong)*olen); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
crypt->bufsize = *olen; |
|||
} |
|||
|
|||
if (*elen > 0) { |
|||
if (crypt->read(crypt->userdata, crypt->buffer, *elen) |
|||
!= *elen) { |
|||
msg("%s:%s: failed to read %lld bytes for chunk payload " |
|||
"at offset 0x%llx.\n", my_progname, __FUNCTION__, |
|||
(ulonglong)*elen, crypt->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
} |
|||
|
|||
checksum = crc32_iso3309(0, crypt->buffer, *elen); |
|||
if (checksum != checksum_exp) { |
|||
msg("%s:%s invalid checksum at offset 0x%llx, " |
|||
"expected 0x%lx, actual 0x%lx.\n", my_progname, __FUNCTION__, |
|||
crypt->offset, checksum_exp, checksum); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
|
|||
crypt->offset += *elen; |
|||
*buf = crypt->buffer; |
|||
|
|||
*hash_appended = version > 2; |
|||
|
|||
goto exit; |
|||
|
|||
err: |
|||
*buf = NULL; |
|||
*olen = 0; |
|||
*elen = 0; |
|||
*ivlen = 0; |
|||
*iv = 0; |
|||
exit: |
|||
return result; |
|||
} |
|||
|
|||
int xb_crypt_read_close(xb_rcrypt_t *crypt) |
|||
{ |
|||
if (crypt->buffer) |
|||
my_free(crypt->buffer); |
|||
if (crypt->ivbuffer) |
|||
my_free(crypt->ivbuffer); |
|||
my_free(crypt); |
|||
|
|||
return 0; |
|||
} |
|||
|
@ -0,0 +1,105 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2013 Percona LLC and/or its affiliates. |
|||
|
|||
The xbcrypt format writer implementation. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include "xbcrypt.h" |
|||
#include "crc_glue.h" |
|||
|
|||
struct xb_wcrypt_struct { |
|||
void *userdata; |
|||
xb_crypt_write_callback *write; |
|||
}; |
|||
|
|||
xb_wcrypt_t * |
|||
xb_crypt_write_open(void *userdata, xb_crypt_write_callback *onwrite) |
|||
{ |
|||
xb_wcrypt_t *crypt; |
|||
|
|||
xb_ad(onwrite); |
|||
|
|||
crypt = (xb_wcrypt_t *) my_malloc(sizeof(xb_wcrypt_t), MYF(MY_FAE)); |
|||
|
|||
crypt->userdata = userdata; |
|||
crypt->write = onwrite; |
|||
|
|||
return crypt; |
|||
} |
|||
|
|||
int xb_crypt_write_chunk(xb_wcrypt_t *crypt, const void *buf, size_t olen, |
|||
size_t elen, const void *iv, size_t ivlen) |
|||
{ |
|||
uchar tmpbuf[XB_CRYPT_CHUNK_MAGIC_SIZE + 8 + 8 + 8 + 4 + 8]; |
|||
uchar *ptr; |
|||
ulong checksum; |
|||
|
|||
xb_ad(olen <= INT_MAX); |
|||
if (olen > INT_MAX) |
|||
return 0; |
|||
|
|||
xb_ad(elen <= INT_MAX); |
|||
if (elen > INT_MAX) |
|||
return 0; |
|||
|
|||
xb_ad(ivlen <= INT_MAX); |
|||
if (ivlen > INT_MAX) |
|||
return 0; |
|||
|
|||
ptr = tmpbuf; |
|||
|
|||
memcpy(ptr, XB_CRYPT_CHUNK_MAGIC_CURRENT, XB_CRYPT_CHUNK_MAGIC_SIZE); |
|||
ptr += XB_CRYPT_CHUNK_MAGIC_SIZE; |
|||
|
|||
int8store(ptr, (ulonglong)0); /* reserved */ |
|||
ptr += 8; |
|||
|
|||
int8store(ptr, (ulonglong)olen); /* original size */ |
|||
ptr += 8; |
|||
|
|||
int8store(ptr, (ulonglong)elen); /* encrypted (actual) size */ |
|||
ptr += 8; |
|||
|
|||
checksum = crc32_iso3309(0, buf, elen); |
|||
int4store(ptr, checksum); /* checksum */ |
|||
ptr += 4; |
|||
|
|||
int8store(ptr, (ulonglong)ivlen); /* iv size */ |
|||
ptr += 8; |
|||
|
|||
xb_ad(ptr <= tmpbuf + sizeof(tmpbuf)); |
|||
|
|||
if (crypt->write(crypt->userdata, tmpbuf, ptr-tmpbuf) == -1) |
|||
return 1; |
|||
|
|||
if (crypt->write(crypt->userdata, iv, ivlen) == -1) |
|||
return 1; |
|||
|
|||
if (crypt->write(crypt->userdata, buf, elen) == -1) |
|||
return 1; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
int xb_crypt_write_close(xb_wcrypt_t *crypt) |
|||
{ |
|||
my_free(crypt); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
@ -0,0 +1,613 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2011-2013 Percona LLC and/or its affiliates. |
|||
|
|||
The xbstream utility: serialize/deserialize files in the XBSTREAM format. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include <mysql_version.h> |
|||
#include <my_base.h> |
|||
#include <my_getopt.h> |
|||
#include <hash.h> |
|||
#include <my_pthread.h> |
|||
#include "common.h" |
|||
#include "xbstream.h" |
|||
#include "xbcrypt_common.h" |
|||
#include "datasink.h" |
|||
#include "ds_decrypt.h" |
|||
#include "crc_glue.h" |
|||
|
|||
#define XBSTREAM_VERSION "1.0" |
|||
#define XBSTREAM_BUFFER_SIZE (10 * 1024 * 1024UL) |
|||
|
|||
#define START_FILE_HASH_SIZE 16 |
|||
|
|||
typedef enum { |
|||
RUN_MODE_NONE, |
|||
RUN_MODE_CREATE, |
|||
RUN_MODE_EXTRACT |
|||
} run_mode_t; |
|||
|
|||
const char *xbstream_encrypt_algo_names[] = |
|||
{ "NONE", "AES128", "AES192", "AES256", NullS}; |
|||
TYPELIB xbstream_encrypt_algo_typelib= |
|||
{array_elements(xbstream_encrypt_algo_names)-1,"", |
|||
xbstream_encrypt_algo_names, NULL}; |
|||
|
|||
/* Need the following definitions to avoid linking with ds_*.o and their link |
|||
dependencies */ |
|||
datasink_t datasink_archive; |
|||
datasink_t datasink_xbstream; |
|||
datasink_t datasink_compress; |
|||
datasink_t datasink_tmpfile; |
|||
datasink_t datasink_encrypt; |
|||
datasink_t datasink_buffer; |
|||
|
|||
static run_mode_t opt_mode; |
|||
static char * opt_directory = NULL; |
|||
static my_bool opt_verbose = 0; |
|||
static int opt_parallel = 1; |
|||
static ulong opt_encrypt_algo; |
|||
static char *opt_encrypt_key_file = NULL; |
|||
static void *opt_encrypt_key = NULL; |
|||
static int opt_encrypt_threads = 1; |
|||
|
|||
enum { |
|||
OPT_ENCRYPT_THREADS = 256 |
|||
}; |
|||
|
|||
static struct my_option my_long_options[] = |
|||
{ |
|||
{"help", '?', "Display this help and exit.", |
|||
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
|||
{"create", 'c', "Stream the specified files to the standard output.", |
|||
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
|||
{"extract", 'x', "Extract to disk files from the stream on the " |
|||
"standard input.", |
|||
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
|||
{"directory", 'C', "Change the current directory to the specified one " |
|||
"before streaming or extracting.", &opt_directory, &opt_directory, 0, |
|||
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|||
{"verbose", 'v', "Print verbose output.", &opt_verbose, &opt_verbose, |
|||
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
|||
{"parallel", 'p', "Number of worker threads for reading / writing.", |
|||
&opt_parallel, &opt_parallel, 0, GET_INT, REQUIRED_ARG, |
|||
1, 1, INT_MAX, 0, 0, 0}, |
|||
{"decrypt", 'd', "Decrypt files ending with .xbcrypt.", |
|||
&opt_encrypt_algo, &opt_encrypt_algo, &xbstream_encrypt_algo_typelib, |
|||
GET_ENUM, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|||
{"encrypt-key", 'k', "Encryption key.", |
|||
&opt_encrypt_key, &opt_encrypt_key, 0, |
|||
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|||
{"encrypt-key-file", 'f', "File which contains encryption key.", |
|||
&opt_encrypt_key_file, &opt_encrypt_key_file, 0, |
|||
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|||
{"encrypt-threads", OPT_ENCRYPT_THREADS, |
|||
"Number of threads for parallel data encryption. " |
|||
"The default value is 1.", |
|||
&opt_encrypt_threads, &opt_encrypt_threads, |
|||
0, GET_INT, REQUIRED_ARG, 1, 1, INT_MAX, 0, 0, 0}, |
|||
|
|||
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} |
|||
}; |
|||
|
|||
typedef struct { |
|||
HASH *filehash; |
|||
xb_rstream_t *stream; |
|||
ds_ctxt_t *ds_ctxt; |
|||
ds_ctxt_t *ds_decrypt_ctxt; |
|||
pthread_mutex_t *mutex; |
|||
} extract_ctxt_t; |
|||
|
|||
typedef struct { |
|||
char *path; |
|||
uint pathlen; |
|||
my_off_t offset; |
|||
ds_file_t *file; |
|||
pthread_mutex_t mutex; |
|||
} file_entry_t; |
|||
|
|||
static int get_options(int *argc, char ***argv); |
|||
static int mode_create(int argc, char **argv); |
|||
static int mode_extract(int n_threads, int argc, char **argv); |
|||
static my_bool get_one_option(int optid, const struct my_option *opt, |
|||
char *argument); |
|||
|
|||
int |
|||
main(int argc, char **argv) |
|||
{ |
|||
MY_INIT(argv[0]); |
|||
|
|||
crc_init(); |
|||
|
|||
if (get_options(&argc, &argv)) { |
|||
goto err; |
|||
} |
|||
|
|||
if (opt_mode == RUN_MODE_NONE) { |
|||
msg("%s: either -c or -x must be specified.\n", my_progname); |
|||
goto err; |
|||
} |
|||
|
|||
/* Change the current directory if -C is specified */ |
|||
if (opt_directory && my_setwd(opt_directory, MYF(MY_WME))) { |
|||
goto err; |
|||
} |
|||
|
|||
if (opt_mode == RUN_MODE_CREATE && mode_create(argc, argv)) { |
|||
goto err; |
|||
} else if (opt_mode == RUN_MODE_EXTRACT && |
|||
mode_extract(opt_parallel, argc, argv)) { |
|||
goto err; |
|||
} |
|||
|
|||
my_cleanup_options(my_long_options); |
|||
|
|||
my_end(0); |
|||
|
|||
return EXIT_SUCCESS; |
|||
err: |
|||
my_cleanup_options(my_long_options); |
|||
|
|||
my_end(0); |
|||
|
|||
exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
static |
|||
int |
|||
get_options(int *argc, char ***argv) |
|||
{ |
|||
int ho_error; |
|||
|
|||
if ((ho_error= handle_options(argc, argv, my_long_options, |
|||
get_one_option))) { |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static |
|||
void |
|||
print_version(void) |
|||
{ |
|||
printf("%s Ver %s for %s (%s)\n", my_progname, XBSTREAM_VERSION, |
|||
SYSTEM_TYPE, MACHINE_TYPE); |
|||
} |
|||
|
|||
static |
|||
void |
|||
usage(void) |
|||
{ |
|||
print_version(); |
|||
puts("Copyright (C) 2011-2013 Percona LLC and/or its affiliates."); |
|||
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("Serialize/deserialize files in the XBSTREAM format.\n"); |
|||
|
|||
puts("Usage: "); |
|||
printf(" %s -c [OPTIONS...] FILES... # stream specified files to " |
|||
"standard output.\n", my_progname); |
|||
printf(" %s -x [OPTIONS...] # extract files from the stream" |
|||
"on the standard input.\n", my_progname); |
|||
|
|||
puts("\nOptions:"); |
|||
my_print_help(my_long_options); |
|||
} |
|||
|
|||
static |
|||
int |
|||
set_run_mode(run_mode_t mode) |
|||
{ |
|||
if (opt_mode != RUN_MODE_NONE) { |
|||
msg("%s: can't set specify both -c and -x.\n", my_progname); |
|||
return 1; |
|||
} |
|||
|
|||
opt_mode = mode; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static |
|||
my_bool |
|||
get_one_option(int optid, const struct my_option *opt __attribute__((unused)), |
|||
char *argument __attribute__((unused))) |
|||
{ |
|||
switch (optid) { |
|||
case 'c': |
|||
if (set_run_mode(RUN_MODE_CREATE)) { |
|||
return TRUE; |
|||
} |
|||
break; |
|||
case 'x': |
|||
if (set_run_mode(RUN_MODE_EXTRACT)) { |
|||
return TRUE; |
|||
} |
|||
break; |
|||
case '?': |
|||
usage(); |
|||
exit(0); |
|||
} |
|||
|
|||
return FALSE; |
|||
} |
|||
|
|||
static |
|||
int |
|||
stream_one_file(File file, xb_wstream_file_t *xbfile) |
|||
{ |
|||
uchar *buf; |
|||
ssize_t bytes; |
|||
my_off_t offset; |
|||
|
|||
posix_fadvise(file, 0, 0, POSIX_FADV_SEQUENTIAL); |
|||
offset = my_tell(file, MYF(MY_WME)); |
|||
|
|||
buf = (uchar*)(my_malloc(XBSTREAM_BUFFER_SIZE, MYF(MY_FAE))); |
|||
|
|||
while ((bytes = (ssize_t)my_read(file, buf, XBSTREAM_BUFFER_SIZE, |
|||
MYF(MY_WME))) > 0) { |
|||
if (xb_stream_write_data(xbfile, buf, bytes)) { |
|||
msg("%s: xb_stream_write_data() failed.\n", |
|||
my_progname); |
|||
my_free(buf); |
|||
return 1; |
|||
} |
|||
posix_fadvise(file, offset, XBSTREAM_BUFFER_SIZE, |
|||
POSIX_FADV_DONTNEED); |
|||
offset += XBSTREAM_BUFFER_SIZE; |
|||
|
|||
} |
|||
|
|||
my_free(buf); |
|||
|
|||
if (bytes < 0) { |
|||
return 1; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static |
|||
int |
|||
mode_create(int argc, char **argv) |
|||
{ |
|||
int i; |
|||
MY_STAT mystat; |
|||
xb_wstream_t *stream; |
|||
|
|||
if (argc < 1) { |
|||
msg("%s: no files are specified.\n", my_progname); |
|||
return 1; |
|||
} |
|||
|
|||
stream = xb_stream_write_new(); |
|||
if (stream == NULL) { |
|||
msg("%s: xb_stream_write_new() failed.\n", my_progname); |
|||
return 1; |
|||
} |
|||
|
|||
for (i = 0; i < argc; i++) { |
|||
char *filepath = argv[i]; |
|||
File src_file; |
|||
xb_wstream_file_t *file; |
|||
|
|||
if (my_stat(filepath, &mystat, MYF(MY_WME)) == NULL) { |
|||
goto err; |
|||
} |
|||
if (!MY_S_ISREG(mystat.st_mode)) { |
|||
msg("%s: %s is not a regular file, exiting.\n", |
|||
my_progname, filepath); |
|||
goto err; |
|||
} |
|||
|
|||
if ((src_file = my_open(filepath, O_RDONLY, MYF(MY_WME))) < 0) { |
|||
msg("%s: failed to open %s.\n", my_progname, filepath); |
|||
goto err; |
|||
} |
|||
|
|||
file = xb_stream_write_open(stream, filepath, &mystat, NULL, NULL); |
|||
if (file == NULL) { |
|||
goto err; |
|||
} |
|||
|
|||
if (opt_verbose) { |
|||
msg("%s\n", filepath); |
|||
} |
|||
|
|||
if (stream_one_file(src_file, file) || |
|||
xb_stream_write_close(file) || |
|||
my_close(src_file, MYF(MY_WME))) { |
|||
goto err; |
|||
} |
|||
} |
|||
|
|||
xb_stream_write_done(stream); |
|||
|
|||
return 0; |
|||
err: |
|||
xb_stream_write_done(stream); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
/************************************************************************ |
|||
Check if string ends with given suffix. |
|||
@return true if string ends with given suffix. */ |
|||
static |
|||
my_bool |
|||
ends_with(const char *str, const char *suffix) |
|||
{ |
|||
size_t suffix_len = strlen(suffix); |
|||
size_t str_len = strlen(str); |
|||
return(str_len >= suffix_len |
|||
&& strcmp(str + str_len - suffix_len, suffix) == 0); |
|||
} |
|||
|
|||
static |
|||
file_entry_t * |
|||
file_entry_new(extract_ctxt_t *ctxt, const char *path, uint pathlen) |
|||
{ |
|||
file_entry_t *entry; |
|||
ds_file_t *file; |
|||
|
|||
entry = (file_entry_t *) my_malloc(sizeof(file_entry_t), |
|||
MYF(MY_WME | MY_ZEROFILL)); |
|||
if (entry == NULL) { |
|||
return NULL; |
|||
} |
|||
|
|||
entry->path = my_strndup(path, pathlen, MYF(MY_WME)); |
|||
if (entry->path == NULL) { |
|||
goto err; |
|||
} |
|||
entry->pathlen = pathlen; |
|||
|
|||
if (ctxt->ds_decrypt_ctxt && ends_with(path, ".xbcrypt")) { |
|||
file = ds_open(ctxt->ds_decrypt_ctxt, path, NULL); |
|||
} else { |
|||
file = ds_open(ctxt->ds_ctxt, path, NULL); |
|||
} |
|||
if (file == NULL) { |
|||
msg("%s: failed to create file.\n", my_progname); |
|||
goto err; |
|||
} |
|||
|
|||
if (opt_verbose) { |
|||
msg("%s\n", entry->path); |
|||
} |
|||
|
|||
entry->file = file; |
|||
|
|||
pthread_mutex_init(&entry->mutex, NULL); |
|||
|
|||
return entry; |
|||
|
|||
err: |
|||
if (entry->path != NULL) { |
|||
my_free(entry->path); |
|||
} |
|||
my_free(entry); |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
static |
|||
uchar * |
|||
get_file_entry_key(file_entry_t *entry, size_t *length, |
|||
my_bool not_used __attribute__((unused))) |
|||
{ |
|||
*length = entry->pathlen; |
|||
return (uchar *) entry->path; |
|||
} |
|||
|
|||
static |
|||
void |
|||
file_entry_free(file_entry_t *entry) |
|||
{ |
|||
pthread_mutex_destroy(&entry->mutex); |
|||
ds_close(entry->file); |
|||
my_free(entry->path); |
|||
my_free(entry); |
|||
} |
|||
|
|||
static |
|||
void * |
|||
extract_worker_thread_func(void *arg) |
|||
{ |
|||
xb_rstream_chunk_t chunk; |
|||
file_entry_t *entry; |
|||
xb_rstream_result_t res; |
|||
|
|||
extract_ctxt_t *ctxt = (extract_ctxt_t *) arg; |
|||
|
|||
my_thread_init(); |
|||
|
|||
memset(&chunk, 0, sizeof(chunk)); |
|||
|
|||
while (1) { |
|||
|
|||
pthread_mutex_lock(ctxt->mutex); |
|||
res = xb_stream_read_chunk(ctxt->stream, &chunk); |
|||
|
|||
if (res != XB_STREAM_READ_CHUNK) { |
|||
pthread_mutex_unlock(ctxt->mutex); |
|||
break; |
|||
} |
|||
|
|||
/* If unknown type and ignorable flag is set, skip this chunk */ |
|||
if (chunk.type == XB_CHUNK_TYPE_UNKNOWN && \ |
|||
!(chunk.flags & XB_STREAM_FLAG_IGNORABLE)) { |
|||
pthread_mutex_unlock(ctxt->mutex); |
|||
continue; |
|||
} |
|||
|
|||
/* See if we already have this file open */ |
|||
entry = (file_entry_t *) my_hash_search(ctxt->filehash, |
|||
(uchar *) chunk.path, |
|||
chunk.pathlen); |
|||
|
|||
if (entry == NULL) { |
|||
entry = file_entry_new(ctxt, |
|||
chunk.path, |
|||
chunk.pathlen); |
|||
if (entry == NULL) { |
|||
pthread_mutex_unlock(ctxt->mutex); |
|||
break; |
|||
} |
|||
if (my_hash_insert(ctxt->filehash, (uchar *) entry)) { |
|||
msg("%s: my_hash_insert() failed.\n", |
|||
my_progname); |
|||
pthread_mutex_unlock(ctxt->mutex); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
pthread_mutex_lock(&entry->mutex); |
|||
|
|||
pthread_mutex_unlock(ctxt->mutex); |
|||
|
|||
res = xb_stream_validate_checksum(&chunk); |
|||
|
|||
if (res != XB_STREAM_READ_CHUNK) { |
|||
pthread_mutex_unlock(&entry->mutex); |
|||
break; |
|||
} |
|||
|
|||
if (chunk.type == XB_CHUNK_TYPE_EOF) { |
|||
pthread_mutex_unlock(&entry->mutex); |
|||
continue; |
|||
} |
|||
|
|||
if (entry->offset != chunk.offset) { |
|||
msg("%s: out-of-order chunk: real offset = 0x%llx, " |
|||
"expected offset = 0x%llx\n", my_progname, |
|||
chunk.offset, entry->offset); |
|||
pthread_mutex_unlock(&entry->mutex); |
|||
res = XB_STREAM_READ_ERROR; |
|||
break; |
|||
} |
|||
|
|||
if (ds_write(entry->file, chunk.data, chunk.length)) { |
|||
msg("%s: my_write() failed.\n", my_progname); |
|||
pthread_mutex_unlock(&entry->mutex); |
|||
res = XB_STREAM_READ_ERROR; |
|||
break; |
|||
} |
|||
|
|||
entry->offset += chunk.length; |
|||
|
|||
pthread_mutex_unlock(&entry->mutex); |
|||
} |
|||
|
|||
if (chunk.data) |
|||
my_free(chunk.data); |
|||
|
|||
my_thread_end(); |
|||
|
|||
return (void *)(res); |
|||
} |
|||
|
|||
|
|||
static |
|||
int |
|||
mode_extract(int n_threads, int argc __attribute__((unused)), |
|||
char **argv __attribute__((unused))) |
|||
{ |
|||
xb_rstream_t *stream = NULL; |
|||
HASH filehash; |
|||
ds_ctxt_t *ds_ctxt = NULL; |
|||
ds_ctxt_t *ds_decrypt_ctxt = NULL; |
|||
extract_ctxt_t ctxt; |
|||
int i; |
|||
pthread_t *tids = NULL; |
|||
void **retvals = NULL; |
|||
pthread_mutex_t mutex; |
|||
int ret = 0; |
|||
|
|||
if (my_hash_init(&filehash, &my_charset_bin, START_FILE_HASH_SIZE, |
|||
0, 0, (my_hash_get_key) get_file_entry_key, |
|||
(my_hash_free_key) file_entry_free, MYF(0))) { |
|||
msg("%s: failed to initialize file hash.\n", my_progname); |
|||
return 1; |
|||
} |
|||
|
|||
if (pthread_mutex_init(&mutex, NULL)) { |
|||
msg("%s: failed to initialize mutex.\n", my_progname); |
|||
my_hash_free(&filehash); |
|||
return 1; |
|||
} |
|||
|
|||
/* If --directory is specified, it is already set as CWD by now. */ |
|||
ds_ctxt = ds_create(".", DS_TYPE_LOCAL); |
|||
if (ds_ctxt == NULL) { |
|||
ret = 1; |
|||
goto exit; |
|||
} |
|||
|
|||
|
|||
stream = xb_stream_read_new(); |
|||
if (stream == NULL) { |
|||
msg("%s: xb_stream_read_new() failed.\n", my_progname); |
|||
pthread_mutex_destroy(&mutex); |
|||
ret = 1; |
|||
goto exit; |
|||
} |
|||
|
|||
ctxt.stream = stream; |
|||
ctxt.filehash = &filehash; |
|||
ctxt.ds_ctxt = ds_ctxt; |
|||
ctxt.ds_decrypt_ctxt = ds_decrypt_ctxt; |
|||
ctxt.mutex = &mutex; |
|||
|
|||
tids = malloc(sizeof(pthread_t) * n_threads); |
|||
retvals = malloc(sizeof(void*) * n_threads); |
|||
|
|||
for (i = 0; i < n_threads; i++) |
|||
pthread_create(tids + i, NULL, extract_worker_thread_func, |
|||
&ctxt); |
|||
|
|||
for (i = 0; i < n_threads; i++) |
|||
pthread_join(tids[i], retvals + i); |
|||
|
|||
for (i = 0; i < n_threads; i++) { |
|||
if ((ulong)retvals[i] == XB_STREAM_READ_ERROR) { |
|||
ret = 1; |
|||
goto exit; |
|||
} |
|||
} |
|||
|
|||
exit: |
|||
pthread_mutex_destroy(&mutex); |
|||
|
|||
free(tids); |
|||
free(retvals); |
|||
|
|||
my_hash_free(&filehash); |
|||
if (ds_ctxt != NULL) { |
|||
ds_destroy(ds_ctxt); |
|||
} |
|||
if (ds_decrypt_ctxt) { |
|||
ds_destroy(ds_decrypt_ctxt); |
|||
} |
|||
xb_stream_read_done(stream); |
|||
|
|||
return ret; |
|||
} |
@ -0,0 +1,107 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2011-2017 Percona LLC and/or its affiliates. |
|||
|
|||
The xbstream format interface. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef XBSTREAM_H |
|||
#define XBSTREAM_H |
|||
|
|||
#include <my_base.h> |
|||
|
|||
/* Magic value in a chunk header */ |
|||
#define XB_STREAM_CHUNK_MAGIC "XBSTCK01" |
|||
|
|||
/* Chunk flags */ |
|||
/* Chunk can be ignored if unknown version/format */ |
|||
#define XB_STREAM_FLAG_IGNORABLE 0x01 |
|||
|
|||
/* Magic + flags + type + path len */ |
|||
#define CHUNK_HEADER_CONSTANT_LEN ((sizeof(XB_STREAM_CHUNK_MAGIC) - 1) + \ |
|||
1 + 1 + 4) |
|||
#define CHUNK_TYPE_OFFSET (sizeof(XB_STREAM_CHUNK_MAGIC) - 1 + 1) |
|||
#define PATH_LENGTH_OFFSET (sizeof(XB_STREAM_CHUNK_MAGIC) - 1 + 1 + 1) |
|||
|
|||
typedef struct xb_wstream_struct xb_wstream_t; |
|||
|
|||
typedef struct xb_wstream_file_struct xb_wstream_file_t; |
|||
|
|||
typedef enum { |
|||
XB_STREAM_FMT_NONE, |
|||
XB_STREAM_FMT_TAR, |
|||
XB_STREAM_FMT_XBSTREAM |
|||
} xb_stream_fmt_t; |
|||
|
|||
/************************************************************************ |
|||
Write interface. */ |
|||
|
|||
typedef ssize_t xb_stream_write_callback(xb_wstream_file_t *file, |
|||
void *userdata, |
|||
const void *buf, size_t len); |
|||
|
|||
xb_wstream_t *xb_stream_write_new(void); |
|||
|
|||
xb_wstream_file_t *xb_stream_write_open(xb_wstream_t *stream, const char *path, |
|||
MY_STAT *mystat, void *userdata, |
|||
xb_stream_write_callback *onwrite); |
|||
|
|||
int xb_stream_write_data(xb_wstream_file_t *file, const void *buf, size_t len); |
|||
|
|||
int xb_stream_write_close(xb_wstream_file_t *file); |
|||
|
|||
int xb_stream_write_done(xb_wstream_t *stream); |
|||
|
|||
/************************************************************************ |
|||
Read interface. */ |
|||
|
|||
typedef enum { |
|||
XB_STREAM_READ_CHUNK, |
|||
XB_STREAM_READ_EOF, |
|||
XB_STREAM_READ_ERROR |
|||
} xb_rstream_result_t; |
|||
|
|||
typedef enum { |
|||
XB_CHUNK_TYPE_UNKNOWN = '\0', |
|||
XB_CHUNK_TYPE_PAYLOAD = 'P', |
|||
XB_CHUNK_TYPE_EOF = 'E' |
|||
} xb_chunk_type_t; |
|||
|
|||
typedef struct xb_rstream_struct xb_rstream_t; |
|||
|
|||
typedef struct { |
|||
uchar flags; |
|||
xb_chunk_type_t type; |
|||
uint pathlen; |
|||
char path[FN_REFLEN]; |
|||
size_t length; |
|||
my_off_t offset; |
|||
my_off_t checksum_offset; |
|||
void *data; |
|||
ulong checksum; |
|||
size_t buflen; |
|||
} xb_rstream_chunk_t; |
|||
|
|||
xb_rstream_t *xb_stream_read_new(void); |
|||
|
|||
xb_rstream_result_t xb_stream_read_chunk(xb_rstream_t *stream, |
|||
xb_rstream_chunk_t *chunk); |
|||
|
|||
int xb_stream_read_done(xb_rstream_t *stream); |
|||
|
|||
int xb_stream_validate_checksum(xb_rstream_chunk_t *chunk); |
|||
|
|||
#endif |
@ -0,0 +1,228 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2011-2017 Percona LLC and/or its affiliates. |
|||
|
|||
The xbstream format reader implementation. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include <mysql_version.h> |
|||
#include <my_base.h> |
|||
#include <zlib.h> |
|||
#include "common.h" |
|||
#include "xbstream.h" |
|||
#include "crc_glue.h" |
|||
|
|||
/* Allocate 1 MB for the payload buffer initially */ |
|||
#define INIT_BUFFER_LEN (1024 * 1024) |
|||
|
|||
#ifndef MY_OFF_T_MAX |
|||
#define MY_OFF_T_MAX (~(my_off_t)0UL) |
|||
#endif |
|||
|
|||
struct xb_rstream_struct { |
|||
my_off_t offset; |
|||
File fd; |
|||
}; |
|||
|
|||
xb_rstream_t * |
|||
xb_stream_read_new(void) |
|||
{ |
|||
xb_rstream_t *stream; |
|||
|
|||
stream = (xb_rstream_t *) my_malloc(sizeof(xb_rstream_t), MYF(MY_FAE)); |
|||
|
|||
#ifdef __WIN__ |
|||
setmode(fileno(stdin), _O_BINARY); |
|||
#endif |
|||
|
|||
stream->fd = my_fileno(stdin); |
|||
stream->offset = 0; |
|||
|
|||
return stream; |
|||
} |
|||
|
|||
static inline |
|||
xb_chunk_type_t |
|||
validate_chunk_type(uchar code) |
|||
{ |
|||
switch ((xb_chunk_type_t) code) { |
|||
case XB_CHUNK_TYPE_PAYLOAD: |
|||
case XB_CHUNK_TYPE_EOF: |
|||
return (xb_chunk_type_t) code; |
|||
default: |
|||
return XB_CHUNK_TYPE_UNKNOWN; |
|||
} |
|||
} |
|||
|
|||
int |
|||
xb_stream_validate_checksum(xb_rstream_chunk_t *chunk) |
|||
{ |
|||
ulong checksum; |
|||
|
|||
checksum = crc32_iso3309(0, chunk->data, (uint)chunk->length); |
|||
if (checksum != chunk->checksum) { |
|||
msg("xb_stream_read_chunk(): invalid checksum at offset " |
|||
"0x%llx: expected 0x%lx, read 0x%lx.\n", |
|||
(ulonglong) chunk->checksum_offset, chunk->checksum, |
|||
checksum); |
|||
return XB_STREAM_READ_ERROR; |
|||
} |
|||
|
|||
return XB_STREAM_READ_CHUNK; |
|||
} |
|||
|
|||
#define F_READ(buf,len) \ |
|||
do { \ |
|||
if (xb_read_full(fd, buf, len) < len) { \ |
|||
msg("xb_stream_read_chunk(): my_read() failed.\n"); \ |
|||
goto err; \ |
|||
} \ |
|||
} while (0) |
|||
|
|||
xb_rstream_result_t |
|||
xb_stream_read_chunk(xb_rstream_t *stream, xb_rstream_chunk_t *chunk) |
|||
{ |
|||
uchar tmpbuf[16]; |
|||
uchar *ptr = tmpbuf; |
|||
uint pathlen; |
|||
size_t tbytes; |
|||
ulonglong ullval; |
|||
File fd = stream->fd; |
|||
|
|||
xb_ad(sizeof(tmpbuf) >= CHUNK_HEADER_CONSTANT_LEN); |
|||
|
|||
/* This is the only place where we expect EOF, so read with |
|||
xb_read_full() rather than F_READ() */ |
|||
tbytes = xb_read_full(fd, ptr, CHUNK_HEADER_CONSTANT_LEN); |
|||
if (tbytes == 0) { |
|||
return XB_STREAM_READ_EOF; |
|||
} else if (tbytes < CHUNK_HEADER_CONSTANT_LEN) { |
|||
msg("xb_stream_read_chunk(): unexpected end of stream at " |
|||
"offset 0x%llx.\n", stream->offset); |
|||
goto err; |
|||
} |
|||
|
|||
ptr = tmpbuf; |
|||
|
|||
/* Chunk magic value */ |
|||
if (memcmp(tmpbuf, XB_STREAM_CHUNK_MAGIC, 8)) { |
|||
msg("xb_stream_read_chunk(): wrong chunk magic at offset " |
|||
"0x%llx.\n", (ulonglong) stream->offset); |
|||
goto err; |
|||
} |
|||
ptr += 8; |
|||
stream->offset += 8; |
|||
|
|||
/* Chunk flags */ |
|||
chunk->flags = *ptr++; |
|||
stream->offset++; |
|||
|
|||
/* Chunk type, ignore unknown ones if ignorable flag is set */ |
|||
chunk->type = validate_chunk_type(*ptr); |
|||
if (chunk->type == XB_CHUNK_TYPE_UNKNOWN && |
|||
!(chunk->flags & XB_STREAM_FLAG_IGNORABLE)) { |
|||
msg("xb_stream_read_chunk(): unknown chunk type 0x%lu at " |
|||
"offset 0x%llx.\n", (ulong) *ptr, |
|||
(ulonglong) stream->offset); |
|||
goto err; |
|||
} |
|||
ptr++; |
|||
stream->offset++; |
|||
|
|||
/* Path length */ |
|||
pathlen = uint4korr(ptr); |
|||
if (pathlen >= FN_REFLEN) { |
|||
msg("xb_stream_read_chunk(): path length (%lu) is too large at " |
|||
"offset 0x%llx.\n", (ulong) pathlen, stream->offset); |
|||
goto err; |
|||
} |
|||
chunk->pathlen = pathlen; |
|||
stream->offset +=4; |
|||
|
|||
xb_ad((ptr + 4 - tmpbuf) == CHUNK_HEADER_CONSTANT_LEN); |
|||
|
|||
/* Path */ |
|||
if (chunk->pathlen > 0) { |
|||
F_READ((uchar *) chunk->path, pathlen); |
|||
stream->offset += pathlen; |
|||
} |
|||
chunk->path[pathlen] = '\0'; |
|||
|
|||
if (chunk->type == XB_CHUNK_TYPE_EOF) { |
|||
return XB_STREAM_READ_CHUNK; |
|||
} |
|||
|
|||
/* Payload length */ |
|||
F_READ(tmpbuf, 16); |
|||
ullval = uint8korr(tmpbuf); |
|||
if (ullval > (ulonglong) SIZE_T_MAX) { |
|||
msg("xb_stream_read_chunk(): chunk length is too large at " |
|||
"offset 0x%llx: 0x%llx.\n", (ulonglong) stream->offset, |
|||
ullval); |
|||
goto err; |
|||
} |
|||
chunk->length = (size_t) ullval; |
|||
stream->offset += 8; |
|||
|
|||
/* Payload offset */ |
|||
ullval = uint8korr(tmpbuf + 8); |
|||
if (ullval > (ulonglong) MY_OFF_T_MAX) { |
|||
msg("xb_stream_read_chunk(): chunk offset is too large at " |
|||
"offset 0x%llx: 0x%llx.\n", (ulonglong) stream->offset, |
|||
ullval); |
|||
goto err; |
|||
} |
|||
chunk->offset = (my_off_t) ullval; |
|||
stream->offset += 8; |
|||
|
|||
/* Reallocate the buffer if needed */ |
|||
if (chunk->length > chunk->buflen) { |
|||
chunk->data = my_realloc(chunk->data, chunk->length, |
|||
MYF(MY_WME | MY_ALLOW_ZERO_PTR)); |
|||
if (chunk->data == NULL) { |
|||
msg("xb_stream_read_chunk(): failed to increase buffer " |
|||
"to %lu bytes.\n", (ulong) chunk->length); |
|||
goto err; |
|||
} |
|||
chunk->buflen = chunk->length; |
|||
} |
|||
|
|||
/* Checksum */ |
|||
F_READ(tmpbuf, 4); |
|||
chunk->checksum = uint4korr(tmpbuf); |
|||
chunk->checksum_offset = stream->offset; |
|||
|
|||
/* Payload */ |
|||
if (chunk->length > 0) { |
|||
F_READ(chunk->data, chunk->length); |
|||
stream->offset += chunk->length; |
|||
} |
|||
|
|||
stream->offset += 4; |
|||
|
|||
return XB_STREAM_READ_CHUNK; |
|||
|
|||
err: |
|||
return XB_STREAM_READ_ERROR; |
|||
} |
|||
|
|||
int |
|||
xb_stream_read_done(xb_rstream_t *stream) |
|||
{ |
|||
my_free(stream); |
|||
|
|||
return 0; |
|||
} |
@ -0,0 +1,294 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2011-2017 Percona LLC and/or its affiliates. |
|||
|
|||
The xbstream format writer implementation. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include <mysql_version.h> |
|||
#include <my_base.h> |
|||
#include <zlib.h> |
|||
#include "common.h" |
|||
#include "xbstream.h" |
|||
#include "crc_glue.h" |
|||
|
|||
/* Group writes smaller than this into a single chunk */ |
|||
#define XB_STREAM_MIN_CHUNK_SIZE (10 * 1024 * 1024) |
|||
|
|||
struct xb_wstream_struct { |
|||
pthread_mutex_t mutex; |
|||
}; |
|||
|
|||
struct xb_wstream_file_struct { |
|||
xb_wstream_t *stream; |
|||
char *path; |
|||
size_t path_len; |
|||
char chunk[XB_STREAM_MIN_CHUNK_SIZE]; |
|||
char *chunk_ptr; |
|||
size_t chunk_free; |
|||
my_off_t offset; |
|||
void *userdata; |
|||
xb_stream_write_callback *write; |
|||
}; |
|||
|
|||
static int xb_stream_flush(xb_wstream_file_t *file); |
|||
static int xb_stream_write_chunk(xb_wstream_file_t *file, |
|||
const void *buf, size_t len); |
|||
static int xb_stream_write_eof(xb_wstream_file_t *file); |
|||
|
|||
static |
|||
ssize_t |
|||
xb_stream_default_write_callback(xb_wstream_file_t *file __attribute__((unused)), |
|||
void *userdata __attribute__((unused)), |
|||
const void *buf, size_t len) |
|||
{ |
|||
if (my_write(my_fileno(stdout), buf, len, MYF(MY_WME | MY_NABP))) |
|||
return -1; |
|||
return len; |
|||
} |
|||
|
|||
xb_wstream_t * |
|||
xb_stream_write_new(void) |
|||
{ |
|||
xb_wstream_t *stream; |
|||
|
|||
stream = (xb_wstream_t *) my_malloc(sizeof(xb_wstream_t), MYF(MY_FAE)); |
|||
pthread_mutex_init(&stream->mutex, NULL); |
|||
|
|||
return stream;; |
|||
} |
|||
|
|||
xb_wstream_file_t * |
|||
xb_stream_write_open(xb_wstream_t *stream, const char *path, |
|||
MY_STAT *mystat __attribute__((unused)), |
|||
void *userdata, |
|||
xb_stream_write_callback *onwrite) |
|||
{ |
|||
xb_wstream_file_t *file; |
|||
size_t path_len; |
|||
|
|||
path_len = strlen(path); |
|||
|
|||
if (path_len > FN_REFLEN) { |
|||
msg("xb_stream_write_open(): file path is too long.\n"); |
|||
return NULL; |
|||
} |
|||
|
|||
file = (xb_wstream_file_t *) my_malloc(sizeof(xb_wstream_file_t) + |
|||
path_len + 1, MYF(MY_FAE)); |
|||
|
|||
file->path = (char *) (file + 1); |
|||
#ifdef _WIN32 |
|||
/* Normalize path on Windows, so we can restore elsewhere.*/ |
|||
{ |
|||
int i; |
|||
for (i = 0; ; i++) { |
|||
file->path[i] = (path[i] == '\\') ? '/' : path[i]; |
|||
if (!path[i]) |
|||
break; |
|||
} |
|||
} |
|||
#else |
|||
memcpy(file->path, path, path_len + 1); |
|||
#endif |
|||
file->path_len = path_len; |
|||
|
|||
file->stream = stream; |
|||
file->offset = 0; |
|||
file->chunk_ptr = file->chunk; |
|||
file->chunk_free = XB_STREAM_MIN_CHUNK_SIZE; |
|||
if (onwrite) { |
|||
#ifdef __WIN__ |
|||
setmode(fileno(stdout), _O_BINARY); |
|||
#endif |
|||
file->userdata = userdata; |
|||
file->write = onwrite; |
|||
} else { |
|||
file->userdata = NULL; |
|||
file->write = xb_stream_default_write_callback; |
|||
} |
|||
|
|||
return file; |
|||
} |
|||
|
|||
int |
|||
xb_stream_write_data(xb_wstream_file_t *file, const void *buf, size_t len) |
|||
{ |
|||
if (len < file->chunk_free) { |
|||
memcpy(file->chunk_ptr, buf, len); |
|||
file->chunk_ptr += len; |
|||
file->chunk_free -= len; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
if (xb_stream_flush(file)) |
|||
return 1; |
|||
|
|||
return xb_stream_write_chunk(file, buf, len); |
|||
} |
|||
|
|||
int |
|||
xb_stream_write_close(xb_wstream_file_t *file) |
|||
{ |
|||
if (xb_stream_flush(file) || |
|||
xb_stream_write_eof(file)) { |
|||
my_free(file); |
|||
return 1; |
|||
} |
|||
|
|||
my_free(file); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
int |
|||
xb_stream_write_done(xb_wstream_t *stream) |
|||
{ |
|||
pthread_mutex_destroy(&stream->mutex); |
|||
|
|||
my_free(stream); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static |
|||
int |
|||
xb_stream_flush(xb_wstream_file_t *file) |
|||
{ |
|||
if (file->chunk_ptr == file->chunk) { |
|||
return 0; |
|||
} |
|||
|
|||
if (xb_stream_write_chunk(file, file->chunk, |
|||
file->chunk_ptr - file->chunk)) { |
|||
return 1; |
|||
} |
|||
|
|||
file->chunk_ptr = file->chunk; |
|||
file->chunk_free = XB_STREAM_MIN_CHUNK_SIZE; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static |
|||
int |
|||
xb_stream_write_chunk(xb_wstream_file_t *file, const void *buf, size_t len) |
|||
{ |
|||
/* Chunk magic + flags + chunk type + path_len + path + len + offset + |
|||
checksum */ |
|||
uchar tmpbuf[sizeof(XB_STREAM_CHUNK_MAGIC) - 1 + 1 + 1 + 4 + |
|||
FN_REFLEN + 8 + 8 + 4]; |
|||
uchar *ptr; |
|||
xb_wstream_t *stream = file->stream; |
|||
ulong checksum; |
|||
|
|||
/* Write xbstream header */ |
|||
ptr = tmpbuf; |
|||
|
|||
/* Chunk magic */ |
|||
memcpy(ptr, XB_STREAM_CHUNK_MAGIC, sizeof(XB_STREAM_CHUNK_MAGIC) - 1); |
|||
ptr += sizeof(XB_STREAM_CHUNK_MAGIC) - 1; |
|||
|
|||
*ptr++ = 0; /* Chunk flags */ |
|||
|
|||
*ptr++ = (uchar) XB_CHUNK_TYPE_PAYLOAD; /* Chunk type */ |
|||
|
|||
int4store(ptr, file->path_len); /* Path length */ |
|||
ptr += 4; |
|||
|
|||
memcpy(ptr, file->path, file->path_len); /* Path */ |
|||
ptr += file->path_len; |
|||
|
|||
int8store(ptr, len); /* Payload length */ |
|||
ptr += 8; |
|||
|
|||
checksum = crc32_iso3309(0, buf, (uint)len); /* checksum */ |
|||
|
|||
pthread_mutex_lock(&stream->mutex); |
|||
|
|||
int8store(ptr, file->offset); /* Payload offset */ |
|||
ptr += 8; |
|||
|
|||
int4store(ptr, checksum); |
|||
ptr += 4; |
|||
|
|||
xb_ad(ptr <= tmpbuf + sizeof(tmpbuf)); |
|||
|
|||
if (file->write(file, file->userdata, tmpbuf, ptr-tmpbuf) == -1) |
|||
goto err; |
|||
|
|||
|
|||
if (file->write(file, file->userdata, buf, len) == -1) /* Payload */ |
|||
goto err; |
|||
|
|||
file->offset+= len; |
|||
|
|||
pthread_mutex_unlock(&stream->mutex); |
|||
|
|||
return 0; |
|||
|
|||
err: |
|||
|
|||
pthread_mutex_unlock(&stream->mutex); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
static |
|||
int |
|||
xb_stream_write_eof(xb_wstream_file_t *file) |
|||
{ |
|||
/* Chunk magic + flags + chunk type + path_len + path */ |
|||
uchar tmpbuf[sizeof(XB_STREAM_CHUNK_MAGIC) - 1 + 1 + 1 + 4 + |
|||
FN_REFLEN]; |
|||
uchar *ptr; |
|||
xb_wstream_t *stream = file->stream; |
|||
|
|||
pthread_mutex_lock(&stream->mutex); |
|||
|
|||
/* Write xbstream header */ |
|||
ptr = tmpbuf; |
|||
|
|||
/* Chunk magic */ |
|||
memcpy(ptr, XB_STREAM_CHUNK_MAGIC, sizeof(XB_STREAM_CHUNK_MAGIC) - 1); |
|||
ptr += sizeof(XB_STREAM_CHUNK_MAGIC) - 1; |
|||
|
|||
*ptr++ = 0; /* Chunk flags */ |
|||
|
|||
*ptr++ = (uchar) XB_CHUNK_TYPE_EOF; /* Chunk type */ |
|||
|
|||
int4store(ptr, file->path_len); /* Path length */ |
|||
ptr += 4; |
|||
|
|||
memcpy(ptr, file->path, file->path_len); /* Path */ |
|||
ptr += file->path_len; |
|||
|
|||
xb_ad(ptr <= tmpbuf + sizeof(tmpbuf)); |
|||
|
|||
if (file->write(file, file->userdata, tmpbuf, |
|||
(ulonglong) (ptr - tmpbuf)) == -1) |
|||
goto err; |
|||
|
|||
pthread_mutex_unlock(&stream->mutex); |
|||
|
|||
return 0; |
|||
err: |
|||
|
|||
pthread_mutex_unlock(&stream->mutex); |
|||
|
|||
return 1; |
|||
} |
7498
extra/mariabackup/xtrabackup.cc
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,247 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2011-2015 Percona LLC and/or its affiliates. |
|||
|
|||
Declarations for xtrabackup.cc |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef XB_XTRABACKUP_H |
|||
#define XB_XTRABACKUP_H |
|||
|
|||
#include <my_getopt.h> |
|||
#include "datasink.h" |
|||
#include "xbstream.h" |
|||
#include "changed_page_bitmap.h" |
|||
|
|||
#ifdef __WIN__ |
|||
#define XB_FILE_UNDEFINED NULL |
|||
#else |
|||
#define XB_FILE_UNDEFINED (-1) |
|||
#endif |
|||
|
|||
typedef struct { |
|||
ulint page_size; |
|||
ulint zip_size; |
|||
ulint space_id; |
|||
} xb_delta_info_t; |
|||
|
|||
/* ======== Datafiles iterator ======== */ |
|||
typedef struct { |
|||
fil_system_t *system; |
|||
fil_space_t *space; |
|||
fil_node_t *node; |
|||
ibool started; |
|||
os_ib_mutex_t mutex; |
|||
} datafiles_iter_t; |
|||
|
|||
/* value of the --incremental option */ |
|||
extern lsn_t incremental_lsn; |
|||
|
|||
extern char *xtrabackup_target_dir; |
|||
extern char *xtrabackup_incremental_dir; |
|||
extern char *xtrabackup_incremental_basedir; |
|||
extern char *innobase_data_home_dir; |
|||
extern char *innobase_buffer_pool_filename; |
|||
extern ds_ctxt_t *ds_meta; |
|||
extern ds_ctxt_t *ds_data; |
|||
|
|||
/* The last checkpoint LSN at the backup startup time */ |
|||
extern lsn_t checkpoint_lsn_start; |
|||
|
|||
extern xb_page_bitmap *changed_page_bitmap; |
|||
|
|||
extern char *xtrabackup_incremental; |
|||
extern my_bool xtrabackup_incremental_force_scan; |
|||
|
|||
extern lsn_t metadata_from_lsn; |
|||
extern lsn_t metadata_to_lsn; |
|||
extern lsn_t metadata_last_lsn; |
|||
|
|||
extern xb_stream_fmt_t xtrabackup_stream_fmt; |
|||
extern ibool xtrabackup_stream; |
|||
|
|||
extern char *xtrabackup_tables; |
|||
extern char *xtrabackup_tables_file; |
|||
extern char *xtrabackup_databases; |
|||
extern char *xtrabackup_databases_file; |
|||
extern char *xtrabackup_tables_exclude; |
|||
extern char *xtrabackup_databases_exclude; |
|||
|
|||
extern ibool xtrabackup_compress; |
|||
extern ibool xtrabackup_encrypt; |
|||
|
|||
extern my_bool xtrabackup_backup; |
|||
extern my_bool xtrabackup_prepare; |
|||
extern my_bool xtrabackup_apply_log_only; |
|||
extern my_bool xtrabackup_copy_back; |
|||
extern my_bool xtrabackup_move_back; |
|||
extern my_bool xtrabackup_decrypt_decompress; |
|||
|
|||
extern char *innobase_data_file_path; |
|||
extern char *innobase_doublewrite_file; |
|||
extern char *xtrabackup_encrypt_key; |
|||
extern char *xtrabackup_encrypt_key_file; |
|||
extern longlong innobase_log_file_size; |
|||
extern long innobase_log_files_in_group; |
|||
extern longlong innobase_page_size; |
|||
|
|||
extern const char *xtrabackup_encrypt_algo_names[]; |
|||
extern TYPELIB xtrabackup_encrypt_algo_typelib; |
|||
|
|||
extern int xtrabackup_parallel; |
|||
|
|||
extern my_bool xb_close_files; |
|||
extern const char *xtrabackup_compress_alg; |
|||
#ifdef __cplusplus |
|||
extern "C"{ |
|||
#endif |
|||
extern uint xtrabackup_compress_threads; |
|||
extern ulonglong xtrabackup_compress_chunk_size; |
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
extern ulong xtrabackup_encrypt_algo; |
|||
extern uint xtrabackup_encrypt_threads; |
|||
extern ulonglong xtrabackup_encrypt_chunk_size; |
|||
extern my_bool xtrabackup_export; |
|||
extern char *xtrabackup_incremental_basedir; |
|||
extern char *xtrabackup_extra_lsndir; |
|||
extern char *xtrabackup_incremental_dir; |
|||
extern ulint xtrabackup_log_copy_interval; |
|||
extern char *xtrabackup_stream_str; |
|||
extern long xtrabackup_throttle; |
|||
extern longlong xtrabackup_use_memory; |
|||
|
|||
extern my_bool opt_galera_info; |
|||
extern my_bool opt_slave_info; |
|||
extern my_bool opt_no_lock; |
|||
extern my_bool opt_safe_slave_backup; |
|||
extern my_bool opt_rsync; |
|||
extern my_bool opt_force_non_empty_dirs; |
|||
extern my_bool opt_noversioncheck; |
|||
extern my_bool opt_no_backup_locks; |
|||
extern my_bool opt_decompress; |
|||
extern my_bool opt_remove_original; |
|||
|
|||
extern char *opt_incremental_history_name; |
|||
extern char *opt_incremental_history_uuid; |
|||
|
|||
extern char *opt_user; |
|||
extern char *opt_password; |
|||
extern char *opt_host; |
|||
extern char *opt_defaults_group; |
|||
extern char *opt_socket; |
|||
extern uint opt_port; |
|||
extern char *opt_login_path; |
|||
extern char *opt_log_bin; |
|||
|
|||
extern const char *query_type_names[]; |
|||
|
|||
enum query_type_t {QUERY_TYPE_ALL, QUERY_TYPE_UPDATE, |
|||
QUERY_TYPE_SELECT}; |
|||
|
|||
extern TYPELIB query_type_typelib; |
|||
|
|||
extern ulong opt_lock_wait_query_type; |
|||
extern ulong opt_kill_long_query_type; |
|||
|
|||
extern ulong opt_decrypt_algo; |
|||
|
|||
extern uint opt_kill_long_queries_timeout; |
|||
extern uint opt_lock_wait_timeout; |
|||
extern uint opt_lock_wait_threshold; |
|||
extern uint opt_debug_sleep_before_unlock; |
|||
extern uint opt_safe_slave_backup_timeout; |
|||
|
|||
extern const char *opt_history; |
|||
extern my_bool opt_decrypt; |
|||
|
|||
enum binlog_info_enum { BINLOG_INFO_OFF, BINLOG_INFO_LOCKLESS, BINLOG_INFO_ON, |
|||
BINLOG_INFO_AUTO}; |
|||
|
|||
extern ulong opt_binlog_info; |
|||
|
|||
void xtrabackup_io_throttling(void); |
|||
my_bool xb_write_delta_metadata(const char *filename, |
|||
const xb_delta_info_t *info); |
|||
|
|||
datafiles_iter_t *datafiles_iter_new(fil_system_t *f_system); |
|||
fil_node_t *datafiles_iter_next(datafiles_iter_t *it); |
|||
void datafiles_iter_free(datafiles_iter_t *it); |
|||
|
|||
/************************************************************************ |
|||
Initialize the tablespace memory cache and populate it by scanning for and |
|||
opening data files */ |
|||
ulint xb_data_files_init(void); |
|||
|
|||
/************************************************************************ |
|||
Destroy the tablespace memory cache. */ |
|||
void xb_data_files_close(void); |
|||
|
|||
/*********************************************************************** |
|||
Reads the space flags from a given data file and returns the compressed |
|||
page size, or 0 if the space is not compressed. */ |
|||
ulint xb_get_zip_size(os_file_t file); |
|||
|
|||
/************************************************************************ |
|||
Checks if a table specified as a name in the form "database/name" (InnoDB 5.6) |
|||
or "./database/name.ibd" (InnoDB 5.5-) should be skipped from backup based on |
|||
the --tables or --tables-file options. |
|||
|
|||
@return TRUE if the table should be skipped. */ |
|||
my_bool |
|||
check_if_skip_table( |
|||
/******************/ |
|||
const char* name); /*!< in: path to the table */ |
|||
|
|||
|
|||
/************************************************************************ |
|||
Checks if a database specified by path should be skipped from backup based on |
|||
the --databases, --databases_file or --databases_exclude options. |
|||
|
|||
@return TRUE if the table should be skipped. */ |
|||
my_bool |
|||
check_if_skip_database_by_path( |
|||
const char* path /*!< in: path to the db directory. */ |
|||
); |
|||
|
|||
/************************************************************************ |
|||
Check if parameter is set in defaults file or via command line argument |
|||
@return true if parameter is set. */ |
|||
bool |
|||
check_if_param_set(const char *param); |
|||
|
|||
#if defined(HAVE_OPENSSL) |
|||
extern my_bool opt_use_ssl; |
|||
extern my_bool opt_ssl_verify_server_cert; |
|||
#if !defined(HAVE_YASSL) |
|||
extern char *opt_server_public_key; |
|||
#endif |
|||
#endif |
|||
|
|||
|
|||
void |
|||
xtrabackup_backup_func(void); |
|||
|
|||
my_bool |
|||
xb_get_one_option(int optid, |
|||
const struct my_option *opt __attribute__((unused)), |
|||
char *argument); |
|||
|
|||
const char* |
|||
xb_get_copy_action(const char *dflt = "Copying"); |
|||
|
|||
#endif /* XB_XTRABACKUP_H */ |
@ -0,0 +1,120 @@ |
|||
#ifndef MYSQL_SERVICE_MY_CRYPT_INCLUDED |
|||
#define MYSQL_SERVICE_MY_CRYPT_INCLUDED |
|||
|
|||
/* |
|||
Copyright (c) 2014 Google Inc. |
|||
Copyright (c) 2014, 2015 MariaDB Corporation |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
|||
|
|||
/** |
|||
@file |
|||
my crypt service |
|||
|
|||
AES encryption functions, and a function to generate random bytes. |
|||
|
|||
Include my_config.h before this file to use CTR and GCM modes |
|||
(they only work if server was compiled with openssl). |
|||
*/ |
|||
|
|||
|
|||
#ifdef __cplusplus |
|||
extern "C" { |
|||
#endif |
|||
|
|||
/* return values from my_aes_encrypt/my_aes_decrypt functions */ |
|||
#define MY_AES_OK 0 |
|||
#define MY_AES_BAD_DATA -100 |
|||
#define MY_AES_OPENSSL_ERROR -101 |
|||
#define MY_AES_BAD_KEYSIZE -102 |
|||
|
|||
/* The block size for all supported algorithms */ |
|||
#define MY_AES_BLOCK_SIZE 16 |
|||
|
|||
/* The max key length of all supported algorithms */ |
|||
#define MY_AES_MAX_KEY_LENGTH 32 |
|||
|
|||
#define MY_AES_CTX_SIZE 512 |
|||
|
|||
enum my_aes_mode { |
|||
MY_AES_ECB, MY_AES_CBC |
|||
#ifdef HAVE_EncryptAes128Ctr |
|||
, MY_AES_CTR |
|||
#endif |
|||
#ifdef HAVE_EncryptAes128Gcm |
|||
, MY_AES_GCM |
|||
#endif |
|||
}; |
|||
|
|||
extern struct my_crypt_service_st { |
|||
int (*my_aes_crypt_init)(void *ctx, enum my_aes_mode mode, int flags, |
|||
const unsigned char* key, unsigned int klen, |
|||
const unsigned char* iv, unsigned int ivlen); |
|||
int (*my_aes_crypt_update)(void *ctx, const unsigned char *src, unsigned int slen, |
|||
unsigned char *dst, unsigned int *dlen); |
|||
int (*my_aes_crypt_finish)(void *ctx, unsigned char *dst, unsigned int *dlen); |
|||
int (*my_aes_crypt)(enum my_aes_mode mode, int flags, |
|||
const unsigned char *src, unsigned int slen, unsigned char *dst, unsigned int *dlen, |
|||
const unsigned char *key, unsigned int klen, const unsigned char *iv, unsigned int ivlen); |
|||
unsigned int (*my_aes_get_size)(enum my_aes_mode mode, unsigned int source_length); |
|||
unsigned int (*my_aes_ctx_size)(enum my_aes_mode mode); |
|||
int (*my_random_bytes)(unsigned char* buf, int num); |
|||
} *my_crypt_service; |
|||
|
|||
#ifdef MYSQL_DYNAMIC_PLUGIN |
|||
|
|||
#define my_aes_crypt_init(A,B,C,D,E,F,G) \ |
|||
my_crypt_service->my_aes_crypt_init(A,B,C,D,E,F,G) |
|||
|
|||
#define my_aes_crypt_update(A,B,C,D,E) \ |
|||
my_crypt_service->my_aes_crypt_update(A,B,C,D,E) |
|||
|
|||
#define my_aes_crypt_finish(A,B,C) \ |
|||
my_crypt_service->my_aes_crypt_finish(A,B,C) |
|||
|
|||
#define my_aes_crypt(A,B,C,D,E,F,G,H,I,J) \ |
|||
my_crypt_service->my_aes_crypt(A,B,C,D,E,F,G,H,I,J) |
|||
|
|||
#define my_aes_get_size(A,B)\ |
|||
my_crypt_service->my_aes_get_size(A,B) |
|||
|
|||
#define my_aes_ctx_size(A)\ |
|||
my_crypt_service->my_aes_ctx_size(A) |
|||
|
|||
#define my_random_bytes(A,B)\ |
|||
my_crypt_service->my_random_bytes(A,B) |
|||
|
|||
#else |
|||
|
|||
int my_aes_crypt_init(void *ctx, enum my_aes_mode mode, int flags, |
|||
const unsigned char* key, unsigned int klen, |
|||
const unsigned char* iv, unsigned int ivlen); |
|||
int my_aes_crypt_update(void *ctx, const unsigned char *src, unsigned int slen, |
|||
unsigned char *dst, unsigned int *dlen); |
|||
int my_aes_crypt_finish(void *ctx, unsigned char *dst, unsigned int *dlen); |
|||
int my_aes_crypt(enum my_aes_mode mode, int flags, |
|||
const unsigned char *src, unsigned int slen, unsigned char *dst, unsigned int *dlen, |
|||
const unsigned char *key, unsigned int klen, const unsigned char *iv, unsigned int ivlen); |
|||
|
|||
int my_random_bytes(unsigned char* buf, int num); |
|||
unsigned int my_aes_get_size(enum my_aes_mode mode, unsigned int source_length); |
|||
unsigned int my_aes_ctx_size(enum my_aes_mode mode); |
|||
#endif |
|||
|
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
|
|||
#endif /* MYSQL_SERVICE_MY_CRYPT_INCLUDED */ |
@ -0,0 +1,64 @@ |
|||
/* Copyright (c) 2016, MariaDB |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
|||
|
|||
#ifndef MYSQL_SERVICE_MY_PRINT_ERROR_INCLUDED |
|||
#define MYSQL_SERVICE_MY_PRINT_ERROR_INCLUDED |
|||
|
|||
/** |
|||
@file include/mysql/service_my_print_error.h |
|||
|
|||
This service provides functions for plugins to report |
|||
errors to client (without client, the errors are written to the error log). |
|||
|
|||
*/ |
|||
#ifdef __cplusplus |
|||
extern "C" { |
|||
#endif |
|||
|
|||
#ifndef MYSQL_ABI_CHECK |
|||
#include <stdarg.h> |
|||
#include <stdlib.h> |
|||
#endif |
|||
|
|||
#define ME_ERROR_LOG 64 /* Write the message to the error log */ |
|||
#define ME_NOTE 1024 /* Not an error, just a note */ |
|||
#define ME_WARNING 2048 /* Not an error, just a warning */ |
|||
#define ME_FATAL 4096 /* Fatal statement error */ |
|||
|
|||
extern struct my_print_error_service_st { |
|||
void (*my_error_func)(unsigned int nr, unsigned long MyFlags, ...); |
|||
void (*my_printf_error_func)(unsigned int nr, const char *fmt, unsigned long MyFlags,...); |
|||
void (*my_printv_error_func)(unsigned int error, const char *format, unsigned long MyFlags, va_list ap); |
|||
} *my_print_error_service; |
|||
|
|||
#ifdef MYSQL_DYNAMIC_PLUGIN |
|||
|
|||
#define my_error my_print_error_service->my_error_func |
|||
#define my_printf_error my_print_error_service->my_printf_error_func |
|||
#define my_printv_error(A,B,C,D) my_print_error_service->my_printv_error_func(A,B,C,D) |
|||
|
|||
#else |
|||
|
|||
extern void my_error(unsigned int nr, unsigned long MyFlags, ...); |
|||
extern void my_printf_error(unsigned int my_err, const char *format, unsigned long MyFlags, ...); |
|||
extern void my_printv_error(unsigned int error, const char *format, unsigned long MyFlags,va_list ap); |
|||
#endif |
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
|
|||
#endif |
|||
|
@ -0,0 +1,2 @@ |
|||
#include <service_versions.h> |
|||
SERVICE_VERSION my_crypt_service= (void*)VERSION_my_crypt; |
@ -0,0 +1,17 @@ |
|||
/* Copyright (c) 2016 MariaDB |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
|||
|
|||
#include <service_versions.h> |
|||
SERVICE_VERSION my_print_error_service= (void*)VERSION_my_print_error; |
@ -1,30 +1,39 @@ |
|||
#!/bin/sh -xe |
|||
#!/bin/sh |
|||
|
|||
set -xe |
|||
|
|||
# simply run me from mysql-test/ |
|||
cd std_data/ |
|||
|
|||
# boilerplace for "openssl ca" and /etc/ssl/openssl.cnf |
|||
rm -rf demoCA |
|||
mkdir demoCA demoCA/private demoCA/newcerts |
|||
mkdir demoCA demoCA/newcerts |
|||
touch demoCA/index.txt |
|||
echo 01 > demoCA/serial |
|||
|
|||
# CA certificate, self-signed |
|||
openssl req -x509 -newkey rsa:2048 -keyout demoCA/private/cakey.pem -out cacert.pem -days 7300 -nodes -subj '/CN=cacert/C=FI/ST=Helsinki/L=Helsinki/O=MariaDB' -text |
|||
openssl req -x509 -newkey rsa:2048 -keyout cakey.pem -out cacert.pem -days 7300 -nodes -subj '/CN=cacert/C=FI/ST=Helsinki/L=Helsinki/O=MariaDB' -text |
|||
|
|||
# server certificate signing request and private key. Note the very long subject (for MDEV-7859) |
|||
openssl req -newkey rsa:1024 -keyout server-key.pem -out demoCA/server-req.pem -days 7300 -nodes -subj '/CN=localhost/C=FI/ST=state or province within country, in other certificates in this file it is the same as L/L=location, usually an address but often ambiguously used/OU=organizational unit name, a division name within an organization/O=organization name, typically a company name' |
|||
# convert the key to yassl compatible format |
|||
openssl rsa -in server-key.pem -out server-key.pem |
|||
# sign the server certificate with CA certificate |
|||
openssl ca -days 7300 -batch -cert cacert.pem -policy policy_anything -out server-cert.pem -infiles demoCA/server-req.pem |
|||
openssl ca -keyfile cakey.pem -days 7300 -batch -cert cacert.pem -policy policy_anything -out server-cert.pem -infiles demoCA/server-req.pem |
|||
|
|||
openssl req -newkey rsa:8192 -keyout server8k-key.pem -out demoCA/server8k-req.pem -days 7300 -nodes -subj '/CN=server8k/C=FI/ST=Helsinki/L=Helsinki/O=MariaDB' |
|||
openssl rsa -in server8k-key.pem -out server8k-key.pem |
|||
openssl ca -days 7300 -batch -cert cacert.pem -policy policy_anything -out server8k-cert.pem -infiles demoCA/server8k-req.pem |
|||
openssl ca -keyfile cakey.pem -days 7300 -batch -cert cacert.pem -policy policy_anything -out server8k-cert.pem -infiles demoCA/server8k-req.pem |
|||
|
|||
openssl req -newkey rsa:1024 -keyout client-key.pem -out demoCA/client-req.pem -days 7300 -nodes -subj '/CN=client/C=FI/ST=Helsinki/L=Helsinki/O=MariaDB' |
|||
openssl rsa -in client-key.pem -out client-key.pem |
|||
openssl ca -days 7300 -batch -cert cacert.pem -policy policy_anything -out client-cert.pem -infiles demoCA/client-req.pem |
|||
openssl ca -keyfile cakey.pem -days 7300 -batch -cert cacert.pem -policy policy_anything -out client-cert.pem -infiles demoCA/client-req.pem |
|||
|
|||
# with SubjectAltName, only for OpenSSL 1.0.2+ |
|||
cat > demoCA/sanext.conf <<EOF |
|||
subjectAltName=DNS:localhost |
|||
EOF |
|||
openssl req -newkey rsa:1024 -keyout serversan-key.pem -out demoCA/serversan-req.pem -days 7300 -nodes -subj '/CN=server/C=FI/ST=Helsinki/L=Helsinki/O=MariaDB' |
|||
openssl ca -keyfile cakey.pem -extfile demoCA/sanext.conf -days 7300 -batch -cert cacert.pem -policy policy_anything -out serversan-cert.pem -infiles demoCA/serversan-req.pem |
|||
|
|||
rm -rf demoCA |
@ -1,132 +0,0 @@ |
|||
# |
|||
# Ensure the plugin isn't loaded. |
|||
# |
|||
SELECT * FROM mysql.plugin WHERE dl like 'libdaemon%' ORDER BY name; |
|||
name dl |
|||
# |
|||
# Enable the plugin... |
|||
# |
|||
# |
|||
# Simulate loading a plugin libary with multiple entry points. |
|||
# This will test the DISABLE to ensure all rows are removed. |
|||
# |
|||
INSERT INTO mysql.plugin VALUES ('wicky', 'libdaemon_example.so'); |
|||
INSERT INTO mysql.plugin VALUES ('wacky', 'libdaemon_example.so'); |
|||
INSERT INTO mysql.plugin VALUES ('wonky', 'libdaemon_example.so'); |
|||
# |
|||
# Ensure the plugin is now loaded. |
|||
# |
|||
SELECT * FROM mysql.plugin WHERE dl like 'libdaemon%' ORDER BY name; |
|||
name dl |
|||
daemon_example libdaemon_example.so |
|||
wacky libdaemon_example.so |
|||
wicky libdaemon_example.so |
|||
wonky libdaemon_example.so |
|||
# |
|||
# Ensure the plugin is loaded. |
|||
# |
|||
SELECT * FROM mysql.plugin WHERE dl like '%libdaemon%' ORDER BY name; |
|||
name dl |
|||
daemon_example libdaemon_example.so |
|||
# |
|||
# Ensure the plugin is replaced. |
|||
# |
|||
SELECT * FROM mysql.plugin WHERE dl like '%libdaemon%' ORDER BY name; |
|||
name dl |
|||
daemon_example liblibdaemon_example.so |
|||
# |
|||
# Disable the plugin... |
|||
# |
|||
# |
|||
# Ensure the plugin isn't loaded. |
|||
# |
|||
SELECT * FROM mysql.plugin WHERE dl like '%libdaemon%' ORDER BY name; |
|||
name dl |
|||
# |
|||
# Attempt to load non-existant plugin |
|||
# |
|||
ERROR: Cannot read plugin config file NOT_THERE_AT_ALL. File does not exist. |
|||
# |
|||
# Attempt to use non-existant plugin.ini file |
|||
# |
|||
ERROR: Cannot read plugin config file daemon_example. File does not exist. |
|||
# |
|||
# Attempt to omit the plugin |
|||
# |
|||
ERROR: No plugin specified. |
|||
# |
|||
# Attempt to omit DISABLE|ENABLE |
|||
# |
|||
ERROR: missing operation. Please specify either '<plugin> ENABLE' or '<plugin> DISABLE'. |
|||
# |
|||
# Attempt to use bad paths - datadir |
|||
# |
|||
ERROR: Cannot access datadir at '/data_not_there/'. |
|||
# |
|||
# Attempt to use bad paths - basedir |
|||
# |
|||
ERROR: Cannot access basedir at '/basedir_not_there/'. |
|||
# |
|||
# Attempt to use bad paths - plugin_dir |
|||
# |
|||
ERROR: Cannot read plugin config file daemon_example. File does not exist. |
|||
# |
|||
# Attempt to use bad paths - mysqld |
|||
# |
|||
ERROR: Cannot access mysqld path '/mysqld_not_there/'. |
|||
# |
|||
# Attempt to use bad paths - my_print_defaults |
|||
# |
|||
ERROR: Cannot access my-print-defaults path '/my_print_defaults_not_there/'. |
|||
# |
|||
# Missing library |
|||
# |
|||
ERROR: The plugin library is missing or in a different location. |
|||
# |
|||
# Bad format for config file |
|||
# |
|||
ERROR: Cannot read plugin config file daemon_example. Bad format in plugin configuration file. |
|||
# |
|||
# Missing base_dir option |
|||
# |
|||
ERROR: Missing --basedir option. |
|||
# |
|||
# Missing data_dir option |
|||
# |
|||
ERROR: Missing --datadir option. |
|||
# |
|||
# Missing plugin_dir option |
|||
# |
|||
ERROR: Missing --plugin_dir option. |
|||
# |
|||
# Show the help. |
|||
# |
|||
mysql_plugin Ver V.V.VV Distrib XX.XX.XX |
|||
Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. |
|||
|
|||
Enable or disable plugins. |
|||
|
|||
Usage: mysql_plugin [options] <plugin> ENABLE|DISABLE |
|||
|
|||
Options: |
|||
-?, --help Display this help and exit. |
|||
-b, --basedir=name The basedir for the server. |
|||
-d, --datadir=name The datadir for the server. |
|||
-p, --plugin-dir=name |
|||
The plugin dir for the server. |
|||
-i, --plugin-ini=name |
|||
Read plugin information from configuration file specified |
|||
instead of from <plugin-dir>/<plugin_name>.ini. |
|||
-n, --no-defaults Do not read values from configuration file. |
|||
-P, --print-defaults |
|||
Show default values from configuration file. |
|||
-m, --mysqld=name Path to mysqld executable. Example: /sbin/temp1/mysql/bin |
|||
-f, --my-print-defaults=name |
|||
Path to my_print_defaults executable. Example: |
|||
/source/temp11/extra |
|||
-v, --verbose More verbose output; you can use this multiple times to |
|||
get even more verbose output. |
|||
-V, --version Output version information and exit. |
|||
|
|||
|
|||
mysql_plugin Ver V.V.VV Distrib XX.XX.XX |
@ -1,78 +1,79 @@ |
|||
Certificate: |
|||
Data: |
|||
Version: 3 (0x2) |
|||
Serial Number: 11580370790696127632 (0xa0b5bde0f2c08c90) |
|||
Signature Algorithm: sha1WithRSAEncryption |
|||
Serial Number: |
|||
e5:b1:e3:71:e9:6f:a9:e1 |
|||
Signature Algorithm: sha256WithRSAEncryption |
|||
Issuer: CN=cacert, C=FI, ST=Helsinki, L=Helsinki, O=MariaDB |
|||
Validity |
|||
Not Before: Apr 25 14:55:05 2015 GMT |
|||
Not After : Apr 20 14:55:05 2035 GMT |
|||
Not Before: Apr 25 20:52:21 2017 GMT |
|||
Not After : Apr 20 20:52:21 2037 GMT |
|||
Subject: CN=cacert, C=FI, ST=Helsinki, L=Helsinki, O=MariaDB |
|||
Subject Public Key Info: |
|||
Public Key Algorithm: rsaEncryption |
|||
Public-Key: (2048 bit) |
|||
Modulus: |
|||
00:c0:1f:90:7c:2b:c2:ea:01:93:ce:e0:c5:72:e8: |
|||
1c:06:bd:63:4e:b6:d2:c6:00:32:13:27:42:9e:c9: |
|||
3c:91:33:4d:15:90:67:7d:9d:d8:be:9b:12:e2:f6: |
|||
1b:46:81:4a:8b:10:c5:b8:14:53:ab:6a:2c:c3:7f: |
|||
66:87:6c:0e:18:51:4e:9c:93:7a:6d:a1:d4:06:47: |
|||
58:61:a6:04:21:2c:bd:74:7a:e4:68:45:fe:91:fe: |
|||
fb:a6:29:47:ec:c5:c3:88:c8:c9:e7:d7:c6:1a:0d: |
|||
b8:f5:c5:02:57:25:01:cc:d5:8c:37:46:58:c6:71: |
|||
30:ee:63:38:99:84:5e:9e:3c:af:40:d4:f0:f2:12: |
|||
44:6e:2f:4d:cd:f9:da:4d:0e:1f:a6:fe:35:c3:9d: |
|||
40:08:82:5e:6f:7d:4d:09:16:7d:a1:78:d6:9f:9f: |
|||
44:d6:b1:ad:e7:50:25:1a:f3:4e:16:92:4a:17:5e: |
|||
0b:e1:c8:9f:62:22:c4:e2:01:96:63:ed:37:a2:e5: |
|||
70:b9:dc:c8:8e:c4:fe:00:21:f5:b9:48:c0:43:55: |
|||
4a:d8:0c:9d:ce:d6:60:30:bb:81:31:c8:e9:0e:aa: |
|||
1c:18:3d:e4:10:47:42:17:c0:4d:fb:f5:d9:c2:e4: |
|||
07:33:f7:15:94:63:6d:11:ad:4f:d4:1d:11:41:c1: |
|||
e2:dd |
|||
00:a0:ad:d5:b1:ec:45:6f:d6:33:fc:5a:03:29:14: |
|||
f1:8e:78:d5:27:53:79:e0:92:7c:10:3b:79:a0:d7: |
|||
b6:9d:a8:5c:4d:fa:68:11:b3:03:9e:ee:5e:20:79: |
|||
23:d8:9c:49:34:9c:1d:c4:6e:53:1f:9a:92:1f:08: |
|||
c1:15:e2:ad:cf:59:cd:1e:55:84:79:f9:09:ca:36: |
|||
8a:50:83:c6:38:48:c6:d3:fa:f6:f2:2a:4f:bd:5d: |
|||
60:9d:eb:21:c4:8c:f2:dd:2d:49:10:63:46:47:de: |
|||
2d:59:a0:4a:e0:58:e6:c0:ae:d8:d4:5e:9a:f8:f5: |
|||
68:1d:ea:80:8a:d6:01:b0:d5:5f:30:4d:88:5a:c5: |
|||
1f:81:92:c1:40:54:c8:bb:a6:a1:43:de:81:3c:4b: |
|||
79:95:82:bb:52:da:a3:a4:a0:69:ff:7e:00:8c:86: |
|||
85:ec:af:03:68:a8:83:48:a0:e4:1d:31:a9:5c:47: |
|||
99:9d:3a:3f:b5:3e:12:7c:4d:47:15:72:f1:11:5c: |
|||
4a:ef:08:1c:7b:8f:e6:03:06:07:4f:94:21:b0:5e: |
|||
27:fa:93:8c:b4:cc:56:34:3b:6d:c4:4a:14:57:b2: |
|||
21:1a:3e:2f:c5:9e:47:1a:59:05:22:0e:56:b1:a7: |
|||
e8:80:9b:82:c3:54:57:12:05:94:79:a2:03:d9:64: |
|||
3c:63 |
|||
Exponent: 65537 (0x10001) |
|||
X509v3 extensions: |
|||
X509v3 Subject Key Identifier: |
|||
C7:2C:01:95:1A:F5:3E:CD:04:A6:24:35:35:04:D9:A7:16:01:2A:79 |
|||
1C:C7:2B:AA:1B:B1:BB:2E:9A:F4:0F:B1:86:60:57:38:C2:41:05:12 |
|||
X509v3 Authority Key Identifier: |
|||
keyid:C7:2C:01:95:1A:F5:3E:CD:04:A6:24:35:35:04:D9:A7:16:01:2A:79 |
|||
keyid:1C:C7:2B:AA:1B:B1:BB:2E:9A:F4:0F:B1:86:60:57:38:C2:41:05:12 |
|||
|
|||
X509v3 Basic Constraints: |
|||
CA:TRUE |
|||
Signature Algorithm: sha1WithRSAEncryption |
|||
40:6f:6a:54:f3:29:30:48:46:bd:da:46:71:64:52:14:a7:c2: |
|||
34:b7:5e:1e:42:3d:e7:47:92:cd:87:e7:9d:5d:1a:82:77:82: |
|||
62:32:d4:9d:b6:44:11:dc:88:78:38:a5:d3:1f:1e:be:c2:d6: |
|||
14:b0:58:35:cd:66:22:43:97:ba:bb:e3:44:4f:9d:75:14:9f: |
|||
6f:37:d3:50:07:09:36:bc:58:92:e8:fe:c0:a8:ba:29:55:65: |
|||
e2:6f:8f:ab:a5:1d:4f:56:37:de:c7:b4:39:20:4c:a8:4c:db: |
|||
56:51:12:7e:e7:7f:83:9d:c4:c7:72:8f:6f:83:f0:af:e3:37: |
|||
1c:40:fe:5e:38:26:2f:05:46:a7:0c:a5:81:79:d6:9c:9c:d7: |
|||
56:eb:96:fe:c7:ae:8e:4f:5e:4a:6c:3a:fa:68:be:65:60:a2: |
|||
d3:3f:07:76:45:b3:95:3e:11:ef:3a:0e:6f:73:47:4c:90:dd: |
|||
0b:36:b4:22:df:62:8d:58:d2:a6:34:5b:f0:06:5d:cd:bf:52: |
|||
fa:ee:9b:4f:e8:79:18:6e:1c:6e:5f:96:10:6d:2f:02:1b:dd: |
|||
bf:14:c9:32:3c:83:a5:6e:56:56:78:9d:ce:84:50:a4:df:cc: |
|||
b5:a9:b1:ec:09:07:74:02:27:7a:9d:d2:96:a9:80:95:9a:f2: |
|||
8c:e9:ef:99 |
|||
Signature Algorithm: sha256WithRSAEncryption |
|||
0d:4b:21:52:fa:49:34:56:14:db:83:ae:1c:3d:a7:4d:3e:ea: |
|||
55:7e:1a:37:7a:65:89:ee:19:05:94:9d:3a:ad:59:c4:38:16: |
|||
b2:bd:02:ee:5a:a6:7e:e2:b1:21:a3:ad:af:8c:ae:c3:30:71: |
|||
ad:d7:d2:24:0f:c4:d9:47:80:c5:95:05:1d:7c:8a:49:0a:7d: |
|||
8b:61:ca:b5:68:3d:3e:4e:f1:c7:45:62:c8:cc:a9:2f:f3:12: |
|||
f1:3f:92:34:7f:07:ab:d3:ac:ab:af:2d:c9:69:63:8a:b2:e5: |
|||
35:ea:7d:b8:17:38:72:82:5f:96:3d:dc:8d:e5:11:bb:ae:f3: |
|||
02:2d:20:77:5c:64:59:18:a6:e7:fa:c7:89:e8:30:12:14:04: |
|||
40:5b:e9:b1:8f:86:81:b9:0d:6c:b6:fc:98:f9:b7:52:ab:8f: |
|||
7e:53:c8:a0:05:e4:cd:0d:6b:d2:74:9f:17:7a:a1:c3:76:5e: |
|||
f3:29:1c:c6:be:56:ab:02:f7:5d:e1:c9:21:27:6d:66:7a:41: |
|||
29:49:a3:f8:f5:2a:e7:03:2a:7c:52:4b:f5:46:58:45:be:a4: |
|||
4c:a0:65:37:1d:d8:ac:f8:1f:81:ca:9c:79:f0:ff:22:8c:1d: |
|||
ce:2b:d0:1e:ce:99:f2:db:fa:66:84:e6:86:6f:19:3b:10:f1: |
|||
92:ac:57:b2 |
|||
-----BEGIN CERTIFICATE----- |
|||
MIIDfzCCAmegAwIBAgIJAKC1veDywIyQMA0GCSqGSIb3DQEBBQUAMFYxDzANBgNV |
|||
MIIDfzCCAmegAwIBAgIJAOWx43Hpb6nhMA0GCSqGSIb3DQEBCwUAMFYxDzANBgNV |
|||
BAMMBmNhY2VydDELMAkGA1UEBhMCRkkxETAPBgNVBAgMCEhlbHNpbmtpMREwDwYD |
|||
VQQHDAhIZWxzaW5raTEQMA4GA1UECgwHTWFyaWFEQjAeFw0xNTA0MjUxNDU1MDVa |
|||
Fw0zNTA0MjAxNDU1MDVaMFYxDzANBgNVBAMMBmNhY2VydDELMAkGA1UEBhMCRkkx |
|||
VQQHDAhIZWxzaW5raTEQMA4GA1UECgwHTWFyaWFEQjAeFw0xNzA0MjUyMDUyMjFa |
|||
Fw0zNzA0MjAyMDUyMjFaMFYxDzANBgNVBAMMBmNhY2VydDELMAkGA1UEBhMCRkkx |
|||
ETAPBgNVBAgMCEhlbHNpbmtpMREwDwYDVQQHDAhIZWxzaW5raTEQMA4GA1UECgwH |
|||
TWFyaWFEQjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMAfkHwrwuoB |
|||
k87gxXLoHAa9Y0620sYAMhMnQp7JPJEzTRWQZ32d2L6bEuL2G0aBSosQxbgUU6tq |
|||
LMN/ZodsDhhRTpyTem2h1AZHWGGmBCEsvXR65GhF/pH++6YpR+zFw4jIyefXxhoN |
|||
uPXFAlclAczVjDdGWMZxMO5jOJmEXp48r0DU8PISRG4vTc352k0OH6b+NcOdQAiC |
|||
Xm99TQkWfaF41p+fRNaxredQJRrzThaSShdeC+HIn2IixOIBlmPtN6LlcLncyI7E |
|||
/gAh9blIwENVStgMnc7WYDC7gTHI6Q6qHBg95BBHQhfATfv12cLkBzP3FZRjbRGt |
|||
T9QdEUHB4t0CAwEAAaNQME4wHQYDVR0OBBYEFMcsAZUa9T7NBKYkNTUE2acWASp5 |
|||
MB8GA1UdIwQYMBaAFMcsAZUa9T7NBKYkNTUE2acWASp5MAwGA1UdEwQFMAMBAf8w |
|||
DQYJKoZIhvcNAQEFBQADggEBAEBvalTzKTBIRr3aRnFkUhSnwjS3Xh5CPedHks2H |
|||
551dGoJ3gmIy1J22RBHciHg4pdMfHr7C1hSwWDXNZiJDl7q740RPnXUUn28301AH |
|||
CTa8WJLo/sCouilVZeJvj6ulHU9WN97HtDkgTKhM21ZREn7nf4OdxMdyj2+D8K/j |
|||
NxxA/l44Ji8FRqcMpYF51pyc11brlv7Hro5PXkpsOvpovmVgotM/B3ZFs5U+Ee86 |
|||
Dm9zR0yQ3Qs2tCLfYo1Y0qY0W/AGXc2/Uvrum0/oeRhuHG5flhBtLwIb3b8UyTI8 |
|||
g6VuVlZ4nc6EUKTfzLWpsewJB3QCJ3qd0papgJWa8ozp75k= |
|||
TWFyaWFEQjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKCt1bHsRW/W |
|||
M/xaAykU8Y541SdTeeCSfBA7eaDXtp2oXE36aBGzA57uXiB5I9icSTScHcRuUx+a |
|||
kh8IwRXirc9ZzR5VhHn5Cco2ilCDxjhIxtP69vIqT71dYJ3rIcSM8t0tSRBjRkfe |
|||
LVmgSuBY5sCu2NRemvj1aB3qgIrWAbDVXzBNiFrFH4GSwUBUyLumoUPegTxLeZWC |
|||
u1Lao6Sgaf9+AIyGheyvA2iog0ig5B0xqVxHmZ06P7U+EnxNRxVy8RFcSu8IHHuP |
|||
5gMGB0+UIbBeJ/qTjLTMVjQ7bcRKFFeyIRo+L8WeRxpZBSIOVrGn6ICbgsNUVxIF |
|||
lHmiA9lkPGMCAwEAAaNQME4wHQYDVR0OBBYEFBzHK6obsbsumvQPsYZgVzjCQQUS |
|||
MB8GA1UdIwQYMBaAFBzHK6obsbsumvQPsYZgVzjCQQUSMAwGA1UdEwQFMAMBAf8w |
|||
DQYJKoZIhvcNAQELBQADggEBAA1LIVL6STRWFNuDrhw9p00+6lV+Gjd6ZYnuGQWU |
|||
nTqtWcQ4FrK9Au5apn7isSGjra+MrsMwca3X0iQPxNlHgMWVBR18ikkKfYthyrVo |
|||
PT5O8cdFYsjMqS/zEvE/kjR/B6vTrKuvLclpY4qy5TXqfbgXOHKCX5Y93I3lEbuu |
|||
8wItIHdcZFkYpuf6x4noMBIUBEBb6bGPhoG5DWy2/Jj5t1Krj35TyKAF5M0Na9J0 |
|||
nxd6ocN2XvMpHMa+VqsC913hySEnbWZ6QSlJo/j1KucDKnxSS/VGWEW+pEygZTcd |
|||
2Kz4H4HKnHnw/yKMHc4r0B7OmfLb+maE5oZvGTsQ8ZKsV7I= |
|||
-----END CERTIFICATE----- |
@ -0,0 +1,28 @@ |
|||
-----BEGIN PRIVATE KEY----- |
|||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCgrdWx7EVv1jP8 |
|||
WgMpFPGOeNUnU3ngknwQO3mg17adqFxN+mgRswOe7l4geSPYnEk0nB3EblMfmpIf |
|||
CMEV4q3PWc0eVYR5+QnKNopQg8Y4SMbT+vbyKk+9XWCd6yHEjPLdLUkQY0ZH3i1Z |
|||
oErgWObArtjUXpr49Wgd6oCK1gGw1V8wTYhaxR+BksFAVMi7pqFD3oE8S3mVgrtS |
|||
2qOkoGn/fgCMhoXsrwNoqINIoOQdMalcR5mdOj+1PhJ8TUcVcvERXErvCBx7j+YD |
|||
BgdPlCGwXif6k4y0zFY0O23EShRXsiEaPi/FnkcaWQUiDlaxp+iAm4LDVFcSBZR5 |
|||
ogPZZDxjAgMBAAECggEAWmy6AGFpSmEP7IpzkOEaeAWEX5dY1YtaioAOGPiM6vje |
|||
yXuMqblG5mBbVIcYJ0T85cCd9/fmi7ifVxvEHh7tle2Bw/p4jXQbkFNVT655FR/P |
|||
1Wg9JVeufHFaeETlQgnYe6SKo9BaswNUHkZZHRyq7/D2Ub3UFRt2tq9MG9YIKY1m |
|||
rP9s7E+EDuH9UhYmaWdQfNm8muIXWK8WjicI5+PX0CQ1NtUy6vS7qBzcBzvT0chC |
|||
Jtja29S6Nvg12A96nHsRmQyUaQjRlqosSwiagpc5mZmNeCEUoY+3deIdYIUMSQnf |
|||
judZOKVPq0GOW5Y1U068LGODWaifPkinGBj+04VH0QKBgQDOp/jVCOUdEeqFJ/8m |
|||
wEsfsRIrXvtGJHgbDXcVJ69FwlX+yaKGEuC+4f21uyxPn6GoFw+NKAyTmGKH7VAX |
|||
OFQLrMQ/DMlNbZrCAAFcXMqrnLaVwqMeIIoVNfKAa8u15K40qc+B0it61Nlay5wq |
|||
wvXoSZrdqXSgsI29pav20+8pTQKBgQDHC3l1+gMZ1rCar+5KdVBN1Wq4Xh7cwZw6 |
|||
FxEvyrDCJePEU2L7FpH1pFuB4WpXdBu3CPo70ZgwfqBXn4qLOOI3gTtDHActyiUm |
|||
+WRG62O+5Ye7aLB4xy0MfnKNA2g/yHj1ozwM8kA5JRptAzDnzWfVE0k47/pVAVzt |
|||
E2bZuSykbwKBgQCL6SkMgjMr1T9j20phn/q8gBN/DZUtTe+K0Tj4N5/wqLuz/its |
|||
fkdutG4ipZBAcCDwPnym4qBxJNBAmqiIr/gm11ceILgBFd2azoodUC1etoDfL6Fj |
|||
+j/CUH3X+CM5CJPwz67Pg80wIf7t+7/FK611ELAqtllhmWa9KPcd6yqWWQKBgHh5 |
|||
Xnvk5kmWY3BNOgrBNOjXWu/asA1n9lpGqfVmVlQ8wL6MxiU5xQCMCYL0X/ws37WK |
|||
boMUWmxHyF8gxqd7t5hm1OrKpSG274PGgUZXpRjfLqdlNyLzUzXztvvY6xloCqaK |
|||
tYcUfYDZD0SaINi8v7L9KF2ZCsi2uXsZOjBf30BrAoGAXPPotkw/CkcPQBS13cha |
|||
ZWeeH5NDKBADWXfLfcRUs108c9xw4BYr5yGilSPscN2ZP0/iWONKp/c6/STS54t5 |
|||
lkOKKUbkAFbQu8UKa1J7zrnHZv+Mr4I/iBBy6VkN8Spp2vBI3Ng6jhPIJg3Gum9p |
|||
943wWtAnIhe/UqCRT3a/GZg= |
|||
-----END PRIVATE KEY----- |
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue