~akopytov/percona-xtrabackup/bug1210266-2.1

516.1.1 by George O. Lorch III
Introducing xtrabackup with encryption.
1
/******************************************************
2
Copyright (c) 2011 Percona Ireland Ltd.
3
4
Streaming implementation for XtraBackup.
5
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; version 2 of the License.
9
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU General Public License for more details.
14
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19
*******************************************************/
20
21
#include <my_base.h>
22
#include <archive.h>
23
#include <archive_entry.h>
24
#include "common.h"
25
#include "datasink.h"
26
27
typedef struct {
28
	struct archive	*archive;
29
	ds_file_t	*dest_file;
30
} ds_archive_ctxt_t;
31
32
typedef struct {
33
	struct archive_entry	*entry;
34
	ds_archive_ctxt_t	*archive_ctxt;
35
} ds_archive_file_t;
36
37
38
/***********************************************************************
39
General archive interface */
40
41
static ds_ctxt_t *archive_init(const char *root);
42
static ds_file_t *archive_open(ds_ctxt_t *ctxt, const char *path,
43
			      MY_STAT *mystat);
44
static int archive_write(ds_file_t *file, const void *buf, size_t len);
45
static int archive_close(ds_file_t *file);
46
static void archive_deinit(ds_ctxt_t *ctxt);
47
48
datasink_t datasink_archive = {
49
	&archive_init,
50
	&archive_open,
51
	&archive_write,
52
	&archive_close,
53
	&archive_deinit
54
};
55
56
static
57
int
58
my_archive_open_callback(struct archive *a __attribute__((unused)),
59
		      void *data __attribute__((unused)))
60
{
61
	return ARCHIVE_OK;
62
}
63
64
static
65
ssize_t
66
my_archive_write_callback(struct archive *a __attribute__((unused)),
67
		       void *data, const void *buffer, size_t length)
68
{
69
	ds_archive_ctxt_t	*archive_ctxt;
70
71
	archive_ctxt = (ds_archive_ctxt_t *) data;
72
73
	xb_ad(archive_ctxt != NULL);
74
	xb_ad(archive_ctxt->dest_file != NULL);
75
76
	if (!ds_write(archive_ctxt->dest_file, buffer, length)) {
77
		return length;
78
	}
79
	return -1;
80
}
81
82
static
83
int
84
my_archive_close_callback(struct archive *a __attribute__((unused)),
85
			  void *data __attribute__((unused)))
86
{
87
	return ARCHIVE_OK;
88
}
89
90
static
91
ds_ctxt_t *
92
archive_init(const char *root __attribute__((unused)))
93
{
94
	ds_ctxt_t		*ctxt;
95
	ds_archive_ctxt_t	*archive_ctxt;
96
97
	ctxt = my_malloc(sizeof(ds_ctxt_t) + sizeof(ds_archive_ctxt_t),
98
			 MYF(MY_FAE));
99
	archive_ctxt = (ds_archive_ctxt_t *)(ctxt + 1);
100
101
	struct archive		*a;
102
103
	a = archive_write_new();
104
	if (a == NULL) {
105
		msg("archive_write_new() failed.\n");
106
		goto err;
107
	}
108
109
	archive_ctxt->archive = a;
110
	archive_ctxt->dest_file = NULL;
111
112
	if (archive_write_set_compression_none(a) != ARCHIVE_OK ||
113
	    archive_write_set_format_pax_restricted(a) != ARCHIVE_OK ||
114
	    /* disable internal buffering so we don't have to flush the
115
	    output in xtrabackup */
116
	    archive_write_set_bytes_per_block(a, 0) != ARCHIVE_OK) {
117
		msg("failed to set libarchive archive options: %s\n",
118
		    archive_error_string(a));
119
		archive_write_finish(a);
120
		goto err;
121
	}
122
123
	if (archive_write_open(a, archive_ctxt, my_archive_open_callback,
124
			       my_archive_write_callback,
125
			       my_archive_close_callback) != ARCHIVE_OK) {
126
		msg("cannot open output archive.\n");
127
		return NULL;
128
	}
129
130
	ctxt->ptr = archive_ctxt;
131
132
	return ctxt;
133
134
err:
135
	MY_FREE(ctxt);
136
	return NULL;
137
}
138
139
static
140
ds_file_t *
141
archive_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat)
142
{
143
	ds_archive_ctxt_t	*archive_ctxt;
144
	ds_ctxt_t		*dest_ctxt;
145
	ds_file_t		*file;
146
	ds_archive_file_t	*archive_file;
147
148
	struct archive		*a;
149
	struct archive_entry	*entry;
150
151
	xb_ad(ctxt->pipe_ctxt != NULL);
152
	dest_ctxt = ctxt->pipe_ctxt;
153
154
	archive_ctxt = (ds_archive_ctxt_t *) ctxt->ptr;
155
156
	if (archive_ctxt->dest_file == NULL) {
157
		archive_ctxt->dest_file = ds_open(dest_ctxt, path, mystat);
158
		if (archive_ctxt->dest_file == NULL) {
159
			return NULL;
160
		}
161
	}
162
163
	file = (ds_file_t *) my_malloc(sizeof(ds_file_t) +
164
				       sizeof(ds_archive_file_t),
165
				       MYF(MY_FAE));
166
167
	archive_file = (ds_archive_file_t *) (file + 1);
168
169
	a = archive_ctxt->archive;
170
171
	entry = archive_entry_new();
172
	if (entry == NULL) {
173
		msg("archive_entry_new() failed.\n");
174
		goto err;
175
	}
176
177
	archive_entry_set_size(entry, mystat->st_size);
178
	archive_entry_set_mode(entry, 0660);
179
	archive_entry_set_filetype(entry, AE_IFREG);
180
	archive_entry_set_pathname(entry, path);
181
	archive_entry_set_mtime(entry, mystat->st_mtime, 0);
182
183
	archive_file->entry = entry;
184
	archive_file->archive_ctxt = archive_ctxt;
185
186
	if (archive_write_header(a, entry) != ARCHIVE_OK) {
187
		msg("archive_write_header() failed.\n");
188
		archive_entry_free(entry);
189
		goto err;
190
	}
191
192
	file->ptr = archive_file;
193
	file->path = archive_ctxt->dest_file->path;
194
195
	return file;
196
197
err:
198
	if (archive_ctxt->dest_file) {
199
		ds_close(archive_ctxt->dest_file);
200
		archive_ctxt->dest_file = NULL;
201
	}
202
	MY_FREE(file);
203
204
	return NULL;
205
}
206
207
static
208
int
209
archive_write(ds_file_t *file, const void *buf, size_t len)
210
{
211
	ds_archive_file_t	*archive_file;
212
213
	archive_file = (ds_archive_file_t *) file->ptr;
214
215
	struct archive		*a;
216
217
	a = archive_file->archive_ctxt->archive;
218
219
	xb_ad(archive_file->archive_ctxt->dest_file != NULL);
220
	if (archive_write_data(a, buf, len) < 0) {
221
		msg("archive_write_data() failed: %s (errno = %d)\n",
222
		    archive_error_string(a), archive_errno(a));
223
		return 1;
224
	}
225
226
	return 0;
227
}
228
229
static
230
int
231
archive_close(ds_file_t *file)
232
{
233
	ds_archive_file_t	*archive_file;
234
	int			rc = 0;
235
236
	archive_file = (ds_archive_file_t *)file->ptr;
237
238
	archive_entry_free(archive_file->entry);
239
240
	MY_FREE(file);
241
242
	return rc;
243
}
244
245
static
246
void
247
archive_deinit(ds_ctxt_t *ctxt)
248
{
249
	ds_archive_ctxt_t	*archive_ctxt;
250
251
	archive_ctxt = (ds_archive_ctxt_t *) ctxt->ptr;
252
253
	struct archive *a;
254
255
	a = archive_ctxt->archive;
256
257
	if (archive_write_close(a) != ARCHIVE_OK) {
258
		msg("archive_write_close() failed.\n");
259
	}
260
	archive_write_finish(a);
261
262
	if (archive_ctxt->dest_file) {
263
		ds_close(archive_ctxt->dest_file);
264
		archive_ctxt->dest_file = NULL;
265
	}
266
267
	MY_FREE(ctxt);
268
}