1 /* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #include "azlib.h"
24 #include <string.h>
25 #include <assert.h>
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <m_ctype.h>
29 #include <m_string.h>
30 #include <my_getopt.h>
31 #include <mysql_version.h>
32 #include <welcome_copyright_notice.h> // ORACLE_WELCOME_COPYRIGHT_NOTICE
33
34 #define BUFFER_LEN 1024
35 #define ARCHIVE_ROW_HEADER_SIZE 4
36
37 #define SHOW_VERSION "0.1"
38
39 static void get_options(int *argc,char * * *argv);
40 static void print_version(void);
41 static void usage(void);
42 static const char *opt_tmpdir;
43 static const char *new_auto_increment;
44 unsigned long long new_auto_increment_value;
45 static const char *load_default_groups[]= { "archive_reader", 0 };
46 static char **default_argv;
47 int opt_check, opt_force, opt_quiet, opt_backup= 0, opt_extract_frm;
48 int opt_autoincrement;
49
main(int argc,char * argv[])50 int main(int argc, char *argv[])
51 {
52 unsigned int ret;
53 azio_stream reader_handle;
54
55 MY_INIT(argv[0]);
56 get_options(&argc, &argv);
57
58 if (argc < 1)
59 {
60 printf("No file specified. \n");
61 return 0;
62 }
63
64 if (!(ret= azopen(&reader_handle, argv[0], O_RDONLY|O_BINARY)))
65 {
66 printf("Could not open Archive file\n");
67 return 0;
68 }
69
70 if (opt_autoincrement)
71 {
72 azio_stream writer_handle;
73
74 if (new_auto_increment_value)
75 {
76 if (reader_handle.auto_increment >= new_auto_increment_value)
77 {
78 printf("Value is lower then current value\n");
79 goto end;
80 }
81 }
82 else
83 {
84 new_auto_increment_value= reader_handle.auto_increment + 1;
85 }
86
87 if (!(ret= azopen(&writer_handle, argv[0], O_CREAT|O_RDWR|O_BINARY)))
88 {
89 printf("Could not open file for update: %s\n", argv[0]);
90 goto end;
91 }
92
93 writer_handle.auto_increment= new_auto_increment_value;
94
95 azclose(&writer_handle);
96 azflush(&reader_handle, Z_SYNC_FLUSH);
97 }
98
99 printf("Version %u\n", reader_handle.version);
100 if (reader_handle.version > 2)
101 {
102 printf("\tMinor version %u\n", reader_handle.minor_version);
103 printf("\tStart position %llu\n", (unsigned long long)reader_handle.start);
104 printf("\tBlock size %u\n", reader_handle.block_size);
105 printf("\tRows %llu\n", reader_handle.rows);
106 printf("\tAutoincrement %llu\n", reader_handle.auto_increment);
107 printf("\tCheck Point %llu\n", reader_handle.check_point);
108 printf("\tForced Flushes %llu\n", reader_handle.forced_flushes);
109 printf("\tLongest Row %u\n", reader_handle.longest_row);
110 printf("\tShortest Row %u\n", reader_handle.shortest_row);
111 printf("\tState %s\n", ( reader_handle.dirty ? "dirty" : "clean"));
112 printf("\tFRM stored at %u\n", reader_handle.frm_start_pos);
113 printf("\tComment stored at %u\n", reader_handle.comment_start_pos);
114 printf("\tData starts at %u\n", (unsigned int)reader_handle.start);
115 if (reader_handle.frm_start_pos)
116 printf("\tFRM length %u\n", reader_handle.frm_length);
117 if (reader_handle.comment_start_pos)
118 {
119 char *comment =
120 (char *) malloc(sizeof(char) * reader_handle.comment_length);
121 azread_comment(&reader_handle, comment);
122 printf("\tComment length %u\n\t\t%.*s\n", reader_handle.comment_length,
123 reader_handle.comment_length, comment);
124 free(comment);
125 }
126 }
127 else
128 {
129 goto end;
130 }
131
132 printf("\n");
133
134 if (opt_check)
135 {
136 uchar size_buffer[ARCHIVE_ROW_HEADER_SIZE];
137 int error;
138 unsigned int x;
139 unsigned int read;
140 unsigned int row_len;
141 unsigned long long row_count= 0;
142 char buffer;
143
144 while ((read= azread(&reader_handle, (uchar *)size_buffer,
145 ARCHIVE_ROW_HEADER_SIZE, &error)))
146 {
147 if (error == Z_STREAM_ERROR || (read && read < ARCHIVE_ROW_HEADER_SIZE))
148 {
149 printf("Table is damaged\n");
150 goto end;
151 }
152
153 /* If we read nothing we are at the end of the file */
154 if (read == 0 || read != ARCHIVE_ROW_HEADER_SIZE)
155 break;
156
157 row_len= uint4korr(size_buffer);
158 row_count++;
159
160 if (row_len > reader_handle.longest_row)
161 {
162 printf("Table is damaged, row %llu is invalid\n",
163 row_count);
164 goto end;
165 }
166
167
168 for (read= x= 0; x < row_len ; x++)
169 {
170 read+= (unsigned int)azread(&reader_handle, &buffer, sizeof(char), &error);
171 if (!read)
172 break;
173 }
174
175
176 if (row_len != read)
177 {
178 printf("Row length did not match row (at %llu). %u != %u \n",
179 row_count, row_len, read);
180 goto end;
181 }
182 }
183
184 if (0)
185 {
186 printf("Table is damaged\n");
187 goto end;
188 }
189 else
190 {
191 printf("Found %llu rows\n", row_count);
192 }
193 }
194
195 if (opt_backup)
196 {
197 uchar size_buffer[ARCHIVE_ROW_HEADER_SIZE];
198 int error;
199 unsigned int read;
200 unsigned int row_len;
201 unsigned long long row_count= 0;
202 char *buffer;
203
204 azio_stream writer_handle;
205
206 buffer= (char *)malloc(reader_handle.longest_row);
207 if (buffer == NULL)
208 {
209 printf("Could not allocate memory for row %llu\n", row_count);
210 goto end;
211 }
212
213
214 if (!(ret= azopen(&writer_handle, argv[1], O_CREAT|O_RDWR|O_BINARY)))
215 {
216 printf("Could not open file for backup: %s\n", argv[1]);
217 goto end;
218 }
219
220 writer_handle.auto_increment= reader_handle.auto_increment;
221 if (reader_handle.frm_length)
222 {
223 char *ptr;
224 ptr= (char *)my_malloc(sizeof(char) * reader_handle.frm_length, MYF(0));
225 azread_frm(&reader_handle, ptr);
226 azwrite_frm(&writer_handle, ptr, reader_handle.frm_length);
227 my_free(ptr);
228 }
229
230 if (reader_handle.comment_length)
231 {
232 char *ptr;
233 ptr= (char *)my_malloc(sizeof(char) * reader_handle.comment_length, MYF(0));
234 azread_comment(&reader_handle, ptr);
235 azwrite_comment(&writer_handle, ptr, reader_handle.comment_length);
236 my_free(ptr);
237 }
238
239 while ((read= azread(&reader_handle, (uchar *)size_buffer,
240 ARCHIVE_ROW_HEADER_SIZE, &error)))
241 {
242 if (error == Z_STREAM_ERROR || (read && read < ARCHIVE_ROW_HEADER_SIZE))
243 {
244 printf("Table is damaged\n");
245 goto end;
246 }
247
248 /* If we read nothing we are at the end of the file */
249 if (read == 0 || read != ARCHIVE_ROW_HEADER_SIZE)
250 break;
251
252 row_len= uint4korr(size_buffer);
253
254 row_count++;
255
256 memcpy(buffer, size_buffer, ARCHIVE_ROW_HEADER_SIZE);
257
258 read= (unsigned int)azread(&reader_handle, buffer + ARCHIVE_ROW_HEADER_SIZE,
259 row_len, &error);
260
261 DBUG_ASSERT(read == row_len);
262
263 azwrite(&writer_handle, buffer, row_len + ARCHIVE_ROW_HEADER_SIZE);
264
265
266 if (row_len != read)
267 {
268 printf("Row length did not match row (at %llu). %u != %u \n",
269 row_count, row_len, read);
270 goto end;
271 }
272
273 if (reader_handle.rows == writer_handle.rows)
274 break;
275 }
276
277 free(buffer);
278
279 azclose(&writer_handle);
280 }
281
282 if (opt_extract_frm)
283 {
284 File frm_file;
285 char *ptr;
286 frm_file= my_open(argv[1], O_CREAT|O_RDWR|O_BINARY, MYF(0));
287 ptr= (char *)my_malloc(sizeof(char) * reader_handle.frm_length, MYF(0));
288 azread_frm(&reader_handle, ptr);
289 my_write(frm_file, (uchar*) ptr, reader_handle.frm_length, MYF(0));
290 my_close(frm_file, MYF(0));
291 my_free(ptr);
292 }
293
294 end:
295 printf("\n");
296 azclose(&reader_handle);
297
298 return 0;
299 }
300
301 static my_bool
get_one_option(int optid,const struct my_option * opt MY_ATTRIBUTE ((unused)),char * argument)302 get_one_option(int optid,
303 const struct my_option *opt MY_ATTRIBUTE((unused)),
304 char *argument)
305 {
306 switch (optid) {
307 case 'b':
308 opt_backup= 1;
309 break;
310 case 'c':
311 opt_check= 1;
312 break;
313 case 'e':
314 opt_extract_frm= 1;
315 break;
316 case 'f':
317 opt_force= 1;
318 printf("Not implemented yet\n");
319 break;
320 case 'q':
321 opt_quiet= 1;
322 printf("Not implemented yet\n");
323 break;
324 case 'V':
325 print_version();
326 exit(0);
327 case 't':
328 printf("Not implemented yet\n");
329 break;
330 case 'A':
331 opt_autoincrement= 1;
332 if (argument)
333 new_auto_increment_value= strtoull(argument, NULL, 0);
334 else
335 new_auto_increment_value= 0;
336 break;
337 case '?':
338 usage();
339 exit(0);
340 case '#':
341 if (argument == disabled_my_option)
342 {
343 DBUG_POP();
344 }
345 else
346 {
347 DBUG_PUSH(argument ? argument : "d:t:o,/tmp/archive_reader.trace");
348 }
349 break;
350 }
351 return 0;
352 }
353
354 static struct my_option my_long_options[] =
355 {
356 {"backup", 'b',
357 "Make a backup of an archive table.",
358 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
359 {"check", 'c', "Check table for errors.",
360 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
361 #ifndef DBUG_OFF
362 {"debug", '#',
363 "Output debug log. Often this is 'd:t:o,filename'.",
364 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
365 #endif
366 {"extract-frm", 'e',
367 "Extract the frm file.",
368 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
369 {"force", 'f',
370 "Restart with -r if there are any errors in the table.",
371 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
372 {"help", '?',
373 "Display this help and exit.",
374 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
375 {"quick", 'q', "Faster repair by not modifying the data file.",
376 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
377 {"repair", 'r', "Repair a damaged Archive version 3 or above file.",
378 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
379 {"set-auto-increment", 'A',
380 "Force auto_increment to start at this or higher value. If no value is given, then sets the next auto_increment value to the highest used value for the auto key + 1.",
381 &new_auto_increment, &new_auto_increment,
382 0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0},
383 {"silent", 's',
384 "Only print errors. One can use two -s to make archive_reader very silent.",
385 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
386 {"tmpdir", 't',
387 "Path for temporary files.",
388 &opt_tmpdir,
389 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
390 {"version", 'V',
391 "Print version and exit.",
392 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
393 { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
394 };
395
usage(void)396 static void usage(void)
397 {
398 print_version();
399 puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2007"));
400
401 puts("Read and modify Archive files directly\n");
402 printf("Usage: %s [OPTIONS] file_to_be_looked_at [file_for_backup]\n", my_progname);
403 print_defaults("my", load_default_groups);
404 my_print_help(my_long_options);
405 }
406
print_version(void)407 static void print_version(void)
408 {
409 printf("%s Ver %s Distrib %s, for %s (%s)\n", my_progname, SHOW_VERSION,
410 MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
411 }
412
get_options(int * argc,char *** argv)413 static void get_options(int *argc, char ***argv)
414 {
415 if (load_defaults("my", load_default_groups, argc, argv))
416 exit(1);
417 default_argv= *argv;
418
419 handle_options(argc, argv, my_long_options, get_one_option);
420
421 if (*argc == 0)
422 {
423 usage();
424 exit(-1);
425 }
426
427 return;
428 } /* get options */
429