1 /*
2    Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include <ndb_global.h>
26 
27 #include <NdbTCP.h>
28 #include <NdbOut.hpp>
29 #include "BackupFormat.hpp"
30 #include <AttributeHeader.hpp>
31 #include <SimpleProperties.hpp>
32 #include <util/version.h>
33 #include <ndb_version.h>
34 #include <util/ndbzio.h>
35 
36 #define JAM_FILE_ID 476
37 static const Uint32 MaxReadWords = 32768;
38 
39 bool readHeader(ndbzio_stream*, BackupFormat::FileHeader *);
40 bool readFragHeader(ndbzio_stream*, BackupFormat::DataFile::FragmentHeader *);
41 bool readFragFooter(ndbzio_stream*, BackupFormat::DataFile::FragmentFooter *);
42 Int32 readRecord(ndbzio_stream*, Uint32 **, Uint32*, bool print);
43 
44 NdbOut & operator<<(NdbOut&, const BackupFormat::FileHeader &);
45 NdbOut & operator<<(NdbOut&, const BackupFormat::DataFile::FragmentHeader &);
46 NdbOut & operator<<(NdbOut&, const BackupFormat::DataFile::FragmentFooter &);
47 
48 bool readLCPCtlFile(ndbzio_stream* f, BackupFormat::LCPCtlFile *ret);
49 bool readTableList(ndbzio_stream*, BackupFormat::CtlFile::TableList **);
50 bool readTableDesc(ndbzio_stream*, BackupFormat::CtlFile::TableDescription **);
51 bool readGCPEntry(ndbzio_stream*, BackupFormat::CtlFile::GCPEntry **);
52 
53 NdbOut & operator<<(NdbOut&, const BackupFormat::LCPCtlFile &);
54 NdbOut & operator<<(NdbOut&, const BackupFormat::CtlFile::TableList &);
55 NdbOut & operator<<(NdbOut&, const BackupFormat::CtlFile::TableDescription &);
56 NdbOut & operator<<(NdbOut&, const BackupFormat::CtlFile::GCPEntry &);
57 
58 Int32 readLogEntry(ndbzio_stream*, Uint32**, Uint32 file_type, Uint32 version);
59 
60 struct RowEntry
61 {
62   Uint32 page_id;
63   Uint32 page_idx;
64   RowEntry *prev_ptr;
65   RowEntry *next_ptr;
66 };
67 
68 static Uint32 recNo;
69 static Uint32 recInsert;
70 static Uint32 recWrite;
71 static Uint32 recDeleteByRowId;
72 static Uint32 recDeleteByPageId;
73 static Uint32 logEntryNo;
74 static bool print_restored_rows = false;
75 static int print_restored_rows_table = -1;
76 static int print_restored_rows_fid = -1;
77 static int print_restored_rows_ctl_dir = 0;
78 static int parts_array[BackupFormat::NDB_MAX_LCP_PARTS];
79 static Uint32 max_pages = 0;
80 static int verbose_level = 0;
81 static int already_inserted_count = 0;
82 static int ignored_rows = 0;
83 static int show_ignored_rows = 0;
84 static int print_rows_per_page = 0;
85 static int print_rows_flag = 1;
86 static int num_data_words = 0;
87 static Uint32 all_rows_count = 0;
88 static RowEntry **row_entries = NULL;
89 static RowEntry **row_all_entries = NULL;
90 
91 #define IGNORE_PART 1
92 #define ALL_PART 2
93 #define CHANGE_PART 3
94 
ndb_end_and_exit(int exitcode)95 [[noreturn]] inline void ndb_end_and_exit(int exitcode)
96 {
97   ndb_end(0);
98   exit(exitcode);
99 }
100 
101 Uint32
get_part_id(Uint32 page_id)102 get_part_id(Uint32 page_id)
103 {
104   static Uint32 reverse_3bits_array[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
105   const Uint32 lowest_3bits_page_id = page_id & 7;
106   const Uint32 low_3bits_page_id = (page_id >> 3) & 7;
107   const Uint32 high_3bits_page_id = (page_id >> 6) & 7;
108   const Uint32 highest_3bits_page_id = (page_id >> 9) & 3;
109   Uint32 part_id =
110     reverse_3bits_array[highest_3bits_page_id] +
111     (reverse_3bits_array[high_3bits_page_id] << 3) +
112     (reverse_3bits_array[low_3bits_page_id] << 6) +
113     (reverse_3bits_array[lowest_3bits_page_id] << 9);
114   part_id >>= 1;
115   return part_id;
116 }
117 
118 const char*
get_part_type_string(Uint32 part_type)119 get_part_type_string(Uint32 part_type)
120 {
121   if (part_type == IGNORE_PART)
122     return "IGNORE_PART";
123   if (part_type == ALL_PART)
124     return "ALL_PART";
125   if (part_type == CHANGE_PART)
126     return "CHANGE_PART";
127   assert(false);
128   return "UNKNOWN";
129 }
130 
131 const char*
get_header_string(Uint32 header_type)132 get_header_string(Uint32 header_type)
133 {
134   if (header_type == BackupFormat::INSERT_TYPE)
135     return "INSERT";
136   if (header_type == BackupFormat::WRITE_TYPE)
137     return "WRITE";
138   if (header_type == BackupFormat::DELETE_BY_ROWID_TYPE)
139     return "DELETE_BY_ROWID";
140   if (header_type == BackupFormat::DELETE_BY_PAGEID_TYPE)
141     return "DELETE_BY_PAGEID";
142   assert(false);
143   return "UNKNOWN";
144 }
145 
move_file_back(Uint32 file,Uint32 num_back)146 Uint32 move_file_back(Uint32 file, Uint32 num_back)
147 {
148   if (file >= num_back)
149     return (file - num_back);
150   return (file + BackupFormat::NDB_MAX_LCP_FILES - num_back);
151 }
152 
move_file_forward(Uint32 file,Uint32 num_forward)153 Uint32 move_file_forward(Uint32 file, Uint32 num_forward)
154 {
155   if ((file + num_forward) >= BackupFormat::NDB_MAX_LCP_FILES)
156     return (file + num_forward - BackupFormat::NDB_MAX_LCP_FILES);
157   return (file + num_forward);
158 }
159 
move_part_forward(Uint32 file,Uint32 num_forward)160 Uint32 move_part_forward(Uint32 file, Uint32 num_forward)
161 {
162   if ((file + num_forward) >= BackupFormat::NDB_MAX_LCP_PARTS)
163     return (file + num_forward - BackupFormat::NDB_MAX_LCP_PARTS);
164   return (file + num_forward);
165 }
166 
find_row(Uint32 page_id,Uint32 page_idx,bool is_all)167 RowEntry* find_row(Uint32 page_id,
168                    Uint32 page_idx,
169                    bool is_all)
170 {
171   RowEntry **loc_entries;
172   if (is_all)
173     loc_entries = row_all_entries;
174   else
175     loc_entries = row_entries;
176 
177   if (page_id >= max_pages)
178     return NULL;
179   if (loc_entries[page_id] == NULL)
180     return NULL;
181   RowEntry *current = loc_entries[page_id];
182   do
183   {
184     if (current->page_id != page_id)
185     {
186       ndbout_c("Inconsistent hash table");
187       ndb_end_and_exit(1);
188     }
189     if (current->page_idx == page_idx)
190       return current;
191     current = current->next_ptr;
192   } while (current != NULL);
193   return NULL;
194 }
195 
insert_row(Uint32 page_id,Uint32 page_idx,bool is_insert,bool is_all)196 void insert_row(Uint32 page_id,
197                 Uint32 page_idx,
198                 bool is_insert,
199                 bool is_all)
200 {
201   if (page_id >= max_pages)
202   {
203     ndbout_c("Trying to insert row(%u,%u) beyond max_pages: %u",
204              page_id,
205              page_idx,
206              max_pages);
207     return;
208   }
209   RowEntry *found_row_entry = find_row(page_id, page_idx, is_all);
210   if (found_row_entry != NULL)
211   {
212     if (is_insert && !is_all)
213     {
214       /* Entry already existed */
215       ndbout_c("row(%u,%u) already existed", page_id, page_idx);
216       already_inserted_count++;
217     }
218     return;
219   }
220   RowEntry *new_row_entry = (RowEntry*)malloc(sizeof(struct RowEntry));
221   if (new_row_entry == NULL)
222   {
223     ndbout_c("Malloc failure in insert_row");
224     ndb_end_and_exit(1);
225   }
226   new_row_entry->page_id = page_id;
227   new_row_entry->page_idx = page_idx;
228   new_row_entry->prev_ptr = NULL;
229 
230   RowEntry **loc_entries;
231   if (is_all)
232     loc_entries = row_all_entries;
233   else
234     loc_entries = row_entries;
235 
236   new_row_entry->next_ptr = loc_entries[page_id];
237   if (loc_entries[page_id] != NULL)
238   {
239     loc_entries[page_id]->prev_ptr = new_row_entry;
240   }
241   loc_entries[page_id] = new_row_entry;
242   if (is_all)
243   {
244     all_rows_count++;
245   }
246 }
247 
delete_row(Uint32 page_id,Uint32 page_idx)248 void delete_row(Uint32 page_id, Uint32 page_idx)
249 {
250   if (page_id >= max_pages)
251   {
252     ndbout_c("Trying to delete row(%u,%u) beyond max_pages: %u",
253              page_id,
254              page_idx,
255              max_pages);
256     return;
257   }
258   RowEntry *found_row_entry = find_row(page_id, page_idx, false);
259   if (found_row_entry == NULL)
260   {
261     ndbout_c("Trying to delete row(%u,%u) NOT FOUND",
262              page_id,
263              page_idx);
264     return;
265   }
266   if (found_row_entry->prev_ptr == NULL)
267   {
268     /* First entry in linked list */
269     row_entries[page_id] = found_row_entry->next_ptr;
270   }
271   else
272   {
273     found_row_entry->prev_ptr->next_ptr =
274       found_row_entry->next_ptr;
275   }
276   if (found_row_entry->next_ptr != NULL)
277   {
278     found_row_entry->next_ptr->prev_ptr =
279       found_row_entry->prev_ptr;
280   }
281   free(found_row_entry);
282 }
283 
delete_page(Uint32 page_id)284 void delete_page(Uint32 page_id)
285 {
286   if (page_id >= max_pages)
287   {
288     ndbout_c("Trying to delete page(%u) beyond max_pages: %u",
289              page_id,
290              max_pages);
291     return;
292   }
293   if (row_entries[page_id] == NULL)
294     return;
295   RowEntry *current = row_entries[page_id];
296   row_entries[page_id] = NULL;
297   do
298   {
299     RowEntry *free_row = current;
300     current = current->next_ptr;
301     free(free_row);
302   } while (current != NULL);
303 }
304 
check_data(const char * file_input)305 void check_data(const char *file_input)
306 {
307   FILE *file = fopen(file_input, "r");
308   if (file != NULL)
309   {
310     char line [100];
311     while (fgets(line,sizeof(line),file)!= NULL) /* read a line from a file */
312     {
313       Uint32 page_id, page_idx;
314       int ret = sscanf(line, "%d %d", &page_id, &page_idx);
315       if (ret != 2)
316       {
317         ndbout_c("-n file expects a file with two numbers page_id space page_idx");
318         ndb_end_and_exit(1);
319       }
320       RowEntry *found_entry = find_row(page_id, page_idx, false);
321       if (found_entry != NULL)
322       {
323         ndbout_c("Found deleted row in hash: row_id(%u,%u)",
324                  found_entry->page_id,
325                  found_entry->page_idx);
326       }
327     }
328     fclose(file);
329   }
330 }
331 
print_rows()332 void print_rows()
333 {
334   Uint32 row_count = 0;
335   for (Uint32 page_id = 0; page_id < max_pages; page_id++)
336   {
337     Uint32 rows_page = 0;
338     if (row_entries[page_id] != NULL)
339     {
340       RowEntry *current = row_entries[page_id];
341       do
342       {
343         if (print_rows_flag)
344           ndbout_c("Found row(%u,%u)", page_id, current->page_idx);
345         current = current->next_ptr;
346         row_count++;
347         rows_page++;
348       } while (current != NULL);
349       if (print_rows_per_page && rows_page != 3)
350       {
351         ndbout_c("Rows on page: %u is %u", page_id, rows_page);
352       }
353     }
354   }
355   ndbout_c("Found a total of %u rows after restore", row_count);
356   if (already_inserted_count != 0)
357   {
358     ndbout_c("Found a total of %u rows already existing",
359              already_inserted_count);
360   }
361 }
362 
print_ignored_rows()363 void print_ignored_rows()
364 {
365   ndbout_c("Printing ignored rows");
366   for (Uint32 page_id = 0; page_id < max_pages; page_id++)
367   {
368     if (row_all_entries[page_id] != NULL)
369     {
370       RowEntry *current = row_all_entries[page_id];
371       do
372       {
373         if (!find_row(current->page_id,
374                       current->page_idx,
375                       false))
376         {
377           ndbout_c("Found ignored rowid(%u,%u)",
378                    current->page_id,
379                    current->page_idx);
380         }
381         current = current->next_ptr;
382       } while (current != NULL);
383     }
384   }
385 }
delete_all()386 void delete_all()
387 {
388   for (Uint32 page_id = 0; page_id < max_pages; page_id++)
389   {
390     delete_page(page_id);
391   }
392 }
393 
handle_print_restored_rows(const char * file_input)394 void handle_print_restored_rows(const char *file_input)
395 {
396   ndbout_c("Print restored rows for T%uF%u",
397            print_restored_rows_table,
398            print_restored_rows_fid);
399 
400   char buf[255];
401   ndbzio_stream fo;
402   bzero(&fo, sizeof(fo));
403   BaseString::snprintf(buf, sizeof(buf),
404                        "%u/T%uF%u.ctl",
405                        print_restored_rows_ctl_dir,
406                        print_restored_rows_table,
407                        print_restored_rows_fid);
408   int r = ndbzopen(&fo,buf,O_RDONLY);
409   if(r != 1)
410   {
411     ndbout_c("Failed to open file '%s', error: %d",
412              buf, r);
413     ndb_end_and_exit(1);
414   }
415   ndbzio_stream* f = &fo;
416   BackupFormat::FileHeader fileHeader;
417   if (!readHeader(f, &fileHeader))
418   {
419     ndbout << "Invalid ctl file!" << endl;
420     ndb_end_and_exit(1);
421   }
422   if (fileHeader.FileType != BackupFormat::LCP_CTL_FILE)
423   {
424     ndbout << "Invalid ctl file header!" << endl;
425     ndb_end_and_exit(1);
426   }
427   union
428   {
429     BackupFormat::LCPCtlFile lcpCtlFilePtr;
430     char extra_space[4 * BackupFormat::NDB_MAX_LCP_PARTS];
431   };
432   (void)extra_space;
433   if (!readLCPCtlFile(f, &lcpCtlFilePtr))
434   {
435     ndbout << "Invalid LCP Control file!" << endl;
436     ndb_end_and_exit(1);
437   }
438   ndbzclose(f);
439 
440   /**
441    * Allocate the array of linked list first pointers.
442    */
443   max_pages = lcpCtlFilePtr.MaxPageCount;
444   row_entries = (RowEntry**)malloc(sizeof(RowEntry*) * max_pages);
445   if (row_entries == NULL)
446   {
447     ndbout << "Malloc failure" << endl;
448     ndb_end_and_exit(1);
449   }
450   memset(row_entries, 0, sizeof(RowEntry*) * max_pages);
451 
452   row_all_entries = (RowEntry**)malloc(sizeof(RowEntry*) * max_pages);
453   if (row_all_entries == NULL)
454   {
455     ndbout << "Malloc failure" << endl;
456     ndb_end_and_exit(1);
457   }
458   memset(row_all_entries, 0, sizeof(RowEntry*) * max_pages);
459 
460   Uint32 last_file = lcpCtlFilePtr.LastDataFileNumber;
461   Uint32 num_parts = lcpCtlFilePtr.NumPartPairs;
462   Uint32 current_file = move_file_back(last_file, (num_parts - 1));
463   Uint32 inx = 0;
464   Uint32 first_change = lcpCtlFilePtr.partPairs[inx].startPart;
465   for (Uint32 i = current_file; i <= last_file; i = move_file_forward(i,1))
466   {
467     Uint32 first_all = lcpCtlFilePtr.partPairs[inx].startPart;
468     Uint32 first_ignore =
469       move_part_forward(first_all, lcpCtlFilePtr.partPairs[inx].numParts);
470     inx++;
471     memset(&parts_array[0], 0, sizeof(parts_array));
472     for (Uint32 j = first_change; j != first_all; j = move_part_forward(j,1))
473     {
474       parts_array[j] = CHANGE_PART;
475       assert(j < BackupFormat::NDB_MAX_LCP_PARTS);
476     }
477     for (Uint32 j = first_all; j != first_ignore; j = move_part_forward(j,1))
478     {
479       parts_array[j] = ALL_PART;
480       assert(j < BackupFormat::NDB_MAX_LCP_PARTS);
481     }
482     for (Uint32 j = first_ignore; j != first_change; j = move_part_forward(j,1))
483     {
484       parts_array[j] = IGNORE_PART;
485       assert(j < BackupFormat::NDB_MAX_LCP_PARTS);
486     }
487     for (Uint32 j = 0; j < BackupFormat::NDB_MAX_LCP_PARTS; j++)
488     {
489       assert(parts_array[0] != 0);
490     }
491     ndbout_c("Processing %u/T%uF%u.Data",
492              i,
493              print_restored_rows_table,
494              print_restored_rows_fid);
495     bzero(&fo, sizeof(fo));
496     BaseString::snprintf(buf, sizeof(buf),
497                          "%u/T%uF%u.Data",
498                          i,
499                          print_restored_rows_table,
500                          print_restored_rows_fid);
501     r = ndbzopen(&fo,buf,O_RDONLY);
502     if(r != 1)
503     {
504       ndbout_c("Failed to open file '%s', error: %d",
505                buf, r);
506       //ndb_end_and_exit(1);
507       continue;
508     }
509     if (!readHeader(f, &fileHeader))
510     {
511       ndbout << "Invalid file!" << endl;
512       ndb_end_and_exit(1);
513     }
514     BackupFormat::CtlFile::TableList * tabList;
515     if (!readTableList(f, &tabList))
516     {
517       ndbout << "Invalid file! No table list" << endl;
518       break;
519     }
520     BackupFormat::DataFile::FragmentHeader fragHeader;
521     if (!readFragHeader(f, &fragHeader))
522     {
523       ndbout << "Invalid file! No table list" << endl;
524       break;
525     }
526     Uint32 len, * data, header_type;
527     while((len = readRecord(f, &data, &header_type, (verbose_level > 0))) > 0)
528     {
529       Uint32 page_id = data[0];
530       Uint32 page_idx = data[1];
531       Uint32 part_id = get_part_id(page_id);
532       const char *header_string = get_header_string(header_type);
533       const char *part_string = get_part_type_string(parts_array[part_id]);
534       if (parts_array[part_id] == IGNORE_PART)
535       {
536         if (header_type == BackupFormat::INSERT_TYPE ||
537             header_type == BackupFormat::WRITE_TYPE)
538         {
539           insert_row(page_id, page_idx, true, true);
540           ndbout_c("IGNORE: rowid(%u,%u)", page_id, page_idx);
541           ignored_rows++;
542         }
543         continue;
544       }
545       else if (parts_array[part_id] == ALL_PART)
546       {
547         if (header_type != BackupFormat::INSERT_TYPE)
548         {
549           ndbout_c("NOT INSERT_TYPE when expected");
550           ndb_end_and_exit(1);
551         }
552         if (verbose_level > 0)
553         ndbout_c("%s: page(%u,%u), len: %u, part_id: %u, part_type: %s",
554                  header_string,
555                  page_id,
556                  page_idx,
557                  len,
558                  part_id,
559                  part_string);
560         insert_row(page_id, page_idx, true, true);
561         insert_row(page_id, page_idx, true, false);
562       }
563       else if (parts_array[part_id] != CHANGE_PART)
564       {
565         ndbout_c("NOT CHANGE_PART when expected");
566         ndb_end_and_exit(1);
567       }
568       else
569       {
570         if (header_type == BackupFormat::INSERT_TYPE)
571         {
572           ndbout_c("INSERT_TYPE in CHANGE_PART");
573           ndb_end_and_exit(1);
574         }
575         if (header_type == BackupFormat::DELETE_BY_PAGEID_TYPE)
576         {
577           if (verbose_level > 0)
578           ndbout_c("%s: page(%u), len: %u, part_id: %u, part_type: %s",
579                    header_string,
580                    page_id,
581                    len,
582                    part_id,
583                    part_string);
584           delete_page(page_id);
585         }
586         else if (header_type == BackupFormat::WRITE_TYPE)
587         {
588           if (verbose_level > 0)
589           ndbout_c("%s: page(%u,%u), len: %u, part_id: %u, part_type: %s",
590                    header_string,
591                    page_id,
592                    page_idx,
593                    len,
594                    part_id,
595                    part_string);
596           insert_row(page_id, page_idx, false, false);
597           insert_row(page_id, page_idx, true, true);
598         }
599         else if (header_type == BackupFormat::DELETE_BY_ROWID_TYPE)
600         {
601           if (verbose_level > 0)
602           ndbout_c("%s: page(%u,%u), len: %u, part_id: %u, part_type: %s",
603                    header_string,
604                    page_id,
605                    page_idx,
606                    len,
607                    part_id,
608                    part_string);
609           delete_row(page_id, page_idx);
610         }
611         else
612         {
613           ndbout_c("Wrong header_type: %u in CHANGE_PART", header_type);
614           ndb_end_and_exit(1);
615         }
616       }
617     }
618     ndbzclose(f);
619     ndbout_c("Number of all rows currently are: %u", all_rows_count);
620   }
621   print_rows();
622   if (show_ignored_rows)
623     print_ignored_rows();
624   if (file_input)
625   {
626     check_data(file_input);
627   }
628   delete_all();
629   exit(0);
630 }
631 
632 int
main(int argc,const char * argv[])633 main(int argc, const char * argv[])
634 {
635   const char *file = argv[1];
636   const char *file_input = NULL;
637   ndb_init();
638   if (argc > 2)
639   {
640     for (int i = 1; i < argc; i++)
641     {
642       if (print_restored_rows)
643       {
644         if (!strncmp(argv[i], "-v", 2))
645         {
646           verbose_level++;
647         }
648         else if (!strncmp(argv[i], "-i", 2))
649         {
650           show_ignored_rows = 1;
651         }
652         else if (!strncmp(argv[i], "-p", 2))
653         {
654           print_rows_per_page = 1;
655         }
656         else if (!strncmp(argv[i], "-u", 2))
657         {
658           print_rows_flag = 0;
659         }
660         else if (!strncmp(argv[i], "-h", 2))
661         {
662           if (i + 1 < argc)
663           {
664             int ret = sscanf(argv[i+1], "%d", &num_data_words);
665             if (ret != 1)
666             {
667               printf("Usage: %s <filename>\n", argv[0]);
668               ndb_end_and_exit(1);
669             }
670             i++;
671           }
672           else
673           {
674             printf("Usage: %s <filename>\n", argv[0]);
675             ndb_end_and_exit(1);
676           }
677         }
678         else if (!strncmp(argv[i], "-c", 2))
679         {
680           if (i + 1 < argc)
681           {
682             int ret = sscanf(argv[i+1], "%d", &print_restored_rows_ctl_dir);
683             if (ret != 1 ||
684                 (print_restored_rows_ctl_dir != 0 &&
685                  print_restored_rows_ctl_dir != 1))
686             {
687               printf("Usage: %s <filename>\n", argv[0]);
688               ndb_end_and_exit(1);
689             }
690             i++;
691           }
692           else
693           {
694             printf("Usage: %s <filename>\n", argv[0]);
695             ndb_end_and_exit(1);
696           }
697         }
698         else if (!strncmp(argv[i], "-f", 2))
699         {
700           if (i + 1 < argc)
701           {
702             int ret = sscanf(argv[i+1], "%d", &print_restored_rows_fid);
703             if (ret != 1)
704             {
705               printf("Usage: %s <filename>\n", argv[0]);
706               ndb_end_and_exit(1);
707             }
708             i++;
709           }
710           else if (verbose_level == 0)
711           {
712             printf("Usage: %s <filename>\n", argv[0]);
713             ndb_end_and_exit(1);
714           }
715         }
716         else if (!strncmp(argv[i], "-t", 2))
717         {
718           if (i + 1 < argc)
719           {
720             int ret = sscanf(argv[i+1], "%d", &print_restored_rows_table);
721             if (ret != 1)
722             {
723               printf("Usage: %s <filename>\n", argv[0]);
724               ndb_end_and_exit(1);
725             }
726             i++;
727           }
728           else
729           {
730             printf("Usage: %s <filename>\n", argv[0]);
731             ndb_end_and_exit(1);
732           }
733         }
734         else if (!strncmp(argv[i], "-n", 2))
735         {
736           if (i + 1 < argc)
737           {
738             file_input = argv[i+1];
739             i++;
740           }
741           else
742           {
743             printf("Usage: %s <filename>\n", argv[0]);
744             ndb_end_and_exit(1);
745           }
746         }
747       }
748       else
749       {
750         if (!strncmp(argv[i], "--print-restored-rows", 22))
751         {
752           print_restored_rows = true;
753         }
754         else if (!strncmp(argv[i], "-v", 2))
755         {
756           verbose_level++;
757         }
758         else if (verbose_level == 0)
759         {
760           printf("Usage: %s <filename>\n", argv[0]);
761           ndb_end_and_exit(1);
762         }
763         else if (i + 1 == argc)
764         {
765           file = argv[i];
766         }
767       }
768     }
769   }
770   else if (argc == 2)
771   {
772     ;
773   }
774   else if (argc <= 1)
775   {
776     printf("Usage: %s <filename>\n", argv[0]);
777     ndb_end_and_exit(1);
778   }
779   if (print_restored_rows)
780   {
781     if (print_restored_rows_table == -1 ||
782         print_restored_rows_fid == -1)
783     {
784       printf("Usage: %s <filename>\n", argv[0]);
785       ndb_end_and_exit(1);
786     }
787     handle_print_restored_rows(file_input);
788   }
789 
790   ndbzio_stream fo;
791   bzero(&fo, sizeof(fo));
792   int r= ndbzopen(&fo,file, O_RDONLY);
793 
794   if(r != 1)
795   {
796     ndbout_c("Failed to open file '%s', error: %d",
797              argv[1], r);
798     ndb_end_and_exit(1);
799   }
800 
801   ndbzio_stream* f = &fo;
802 
803   BackupFormat::FileHeader fileHeader;
804   if(!readHeader(f, &fileHeader)){
805     ndbout << "Invalid file!" << endl;
806     ndb_end_and_exit(1);
807   }
808   ndbout << fileHeader << endl;
809 
810   switch(fileHeader.FileType){
811   case BackupFormat::DATA_FILE:
812     while(f->z_eof){
813       BackupFormat::DataFile::FragmentHeader fragHeader;
814       if(!readFragHeader(f, &fragHeader))
815 	break;
816       ndbout << fragHeader << endl;
817 
818       Uint32 len, * data, header_type;
819       while((len = readRecord(f, &data, &header_type, true)) > 0)
820       {
821         if (verbose_level > 0)
822         {
823 	  ndbout << "-> " << hex;
824 	  for(Uint32 i = 0; i < len; i++)
825           {
826 	    ndbout << data[i] << " ";
827           }
828 	  ndbout << endl;
829         }
830       }
831 
832       BackupFormat::DataFile::FragmentFooter fragFooter;
833       if(!readFragFooter(f, &fragFooter))
834 	break;
835       ndbout << fragFooter << endl;
836     }
837     break;
838   case BackupFormat::CTL_FILE:{
839     BackupFormat::CtlFile::TableList * tabList;
840     if(!readTableList(f, &tabList)){
841       ndbout << "Invalid file! No table list" << endl;
842       break;
843     }
844     ndbout << (* tabList) << endl;
845 
846     const Uint32 noOfTables = tabList->SectionLength - 2;
847     for(Uint32 i = 0; i<noOfTables; i++){
848       BackupFormat::CtlFile::TableDescription * tabDesc;
849       if(!readTableDesc(f, &tabDesc)){
850 	ndbout << "Invalid file missing table description" << endl;
851 	break;
852       }
853       ndbout << (* tabDesc) << endl;
854     }
855 
856     BackupFormat::CtlFile::GCPEntry * gcpE;
857     if(!readGCPEntry(f, &gcpE)){
858       ndbout << "Invalid file! GCP ENtry" << endl;
859       break;
860     }
861     ndbout << (* gcpE) << endl;
862 
863     break;
864   }
865   case BackupFormat::LOG_FILE:
866   case BackupFormat::UNDO_FILE:
867   {
868     logEntryNo = 0;
869 
870     const Uint32 log_entry_version =
871         (likely(ndbd_backup_file_fragid(fileHeader.BackupVersion)) ? 2 : 1);
872 
873     typedef BackupFormat::LogFile::LogEntry LogEntry;
874 
875     Int32 dataLen;
876     Uint32 * data;
877     while ((dataLen = readLogEntry(f, &data, fileHeader.FileType, log_entry_version)) > 0)
878     {
879       LogEntry * logEntry = (LogEntry *) data;
880       /**
881        * Log Entry
882        */
883       Uint32 event = ntohl(logEntry->TriggerEvent);
884       bool gcp = (event & 0x10000) != 0;
885       event &= 0xFFFF;
886       if(gcp)
887 	dataLen--;
888 
889       ndbout << "LogEntry Table: " << (Uint32)ntohl(logEntry->TableId)
890 	     << " Event: " << event
891 	     << " Length: " << dataLen;
892 
893       if(gcp)
894 	  ndbout << " GCP: " << (Uint32)ntohl(logEntry->Data[dataLen]);
895       ndbout << endl;
896       if (verbose_level > 0)
897       {
898         Int32 pos = 0;
899         while (pos < dataLen)
900         {
901           AttributeHeader * ah = (AttributeHeader*)&logEntry->Data[pos];
902           ndbout_c(" Attribut: %d Size: %d",
903                    ah->getAttributeId(),
904                    ah->getDataSize());
905           pos += ah->getDataSize() + 1;
906         }
907         require(pos == dataLen);
908       }
909     }
910     require(dataLen == 0);
911     break;
912   }
913   case BackupFormat::LCP_FILE:
914   {
915     BackupFormat::CtlFile::TableList * tabList;
916     if(!readTableList(f, &tabList)){
917       ndbout << "Invalid file! No table list" << endl;
918       break;
919     }
920     ndbout << (* tabList) << endl;
921 
922     if (fileHeader.BackupVersion < NDB_MAKE_VERSION(7,6,4))
923     {
924       const Uint32 noOfTables = tabList->SectionLength - 2;
925       for(Uint32 i = 0; i<noOfTables; i++){
926         BackupFormat::CtlFile::TableDescription * tabDesc;
927         if(!readTableDesc(f, &tabDesc)){
928 	  ndbout << "Invalid file missing table description" << endl;
929 	  break;
930         }
931         ndbout << (* tabDesc) << endl;
932       }
933     }
934     {
935       BackupFormat::DataFile::FragmentHeader fragHeader;
936       if(!readFragHeader(f, &fragHeader))
937 	break;
938       ndbout << fragHeader << endl;
939 
940       Uint32 len, * data, header_type;
941       while((len = readRecord(f, &data, &header_type, true)) > 0)
942       {
943         if (verbose_level > 0)
944         {
945 	  ndbout << "-> " << hex;
946 	  for(Uint32 i = 0; i < len; i++)
947           {
948 	    ndbout << data[i] << " ";
949           }
950           ndbout << endl;
951         }
952       }
953 
954       BackupFormat::DataFile::FragmentFooter fragFooter;
955       if(!readFragFooter(f, &fragFooter))
956 	break;
957       ndbout << fragFooter << endl;
958     }
959     break;
960   }
961   case BackupFormat::LCP_CTL_FILE:
962   {
963     union
964     {
965       BackupFormat::LCPCtlFile lcpCtlFilePtr;
966       char extra_space[4 * BackupFormat::NDB_MAX_LCP_PARTS];
967     };
968     (void)extra_space;
969     if (!readLCPCtlFile(f, &lcpCtlFilePtr))
970     {
971       ndbout << "Invalid LCP Control file!" << endl;
972       break;
973     }
974     ndbout << lcpCtlFilePtr << endl;
975     break;
976   }
977   default:
978     ndbout << "Unsupported file type for printer: "
979 	   << fileHeader.FileType << endl;
980     break;
981   }
982   ndbzclose(f);
983   ndb_end_and_exit(0);
984 }
985 
986 #define RETURN_FALSE() { ndbout_c("false: %d", __LINE__); abort(); return false; }
987 
988 static bool endian = false;
989 
990 static
991 inline
992 size_t
aread(void * buf,size_t sz,size_t n,ndbzio_stream * f)993 aread(void * buf, size_t sz, size_t n, ndbzio_stream* f)
994 {
995   int error = 0;
996   unsigned r = ndbzread(f, buf, (unsigned)(sz * n), &error);
997   if (error || r != (sz * n))
998   {
999     printf("\nFailed to read!!, r = %u, error = %d\n", r, error);
1000     abort();
1001     exit(1);
1002   }
1003   return r / sz;
1004 }
1005 
1006 bool
readHeader(ndbzio_stream * f,BackupFormat::FileHeader * dst)1007 readHeader(ndbzio_stream* f, BackupFormat::FileHeader * dst){
1008   if(aread(dst, 4, 3, f) != 3)
1009     RETURN_FALSE();
1010 
1011   if(memcmp(dst->Magic, BACKUP_MAGIC, sizeof(BACKUP_MAGIC)) != 0)
1012   {
1013     ndbout_c("Incorrect file-header!");
1014     printf("Found:  ");
1015     for (unsigned i = 0; i<sizeof(BACKUP_MAGIC); i++)
1016       printf("0x%.2x ", (Uint32)(Uint8)dst->Magic[i]);
1017     printf("\n");
1018     printf("Expect: ");
1019     for (unsigned i = 0; i<sizeof(BACKUP_MAGIC); i++)
1020       printf("0x%.2x ", (Uint32)(Uint8)BACKUP_MAGIC[i]);
1021     printf("\n");
1022 
1023     RETURN_FALSE();
1024   }
1025 
1026   dst->BackupVersion = ntohl(dst->BackupVersion);
1027   if(dst->BackupVersion > NDB_VERSION)
1028   {
1029     printf("incorrect versions, file: 0x%x expect: 0x%x\n", dst->BackupVersion, NDB_VERSION);
1030     RETURN_FALSE();
1031   }
1032 
1033   if(aread(&dst->SectionType, 4, 2, f) != 2)
1034     RETURN_FALSE();
1035   dst->SectionType = ntohl(dst->SectionType);
1036   dst->SectionLength = ntohl(dst->SectionLength);
1037 
1038   if(dst->SectionType != BackupFormat::FILE_HEADER)
1039     RETURN_FALSE();
1040 
1041   const Uint32 file_header_section_length =
1042     ((dst->BackupVersion < NDBD_RAW_LCP)
1043      ? sizeof(BackupFormat::FileHeader_pre_backup_version)
1044      : sizeof(BackupFormat::FileHeader))/4 - 3;
1045 
1046   if(dst->SectionLength != file_header_section_length)
1047     RETURN_FALSE();
1048 
1049   if(aread(&dst->FileType, 4, dst->SectionLength - 2, f) !=
1050      (dst->SectionLength - 2))
1051     RETURN_FALSE();
1052 
1053   dst->FileType = ntohl(dst->FileType);
1054   dst->BackupId = ntohl(dst->BackupId);
1055   dst->BackupKey_0 = ntohl(dst->BackupKey_0);
1056   dst->BackupKey_1 = ntohl(dst->BackupKey_1);
1057 
1058   if (dst->BackupVersion < NDBD_RAW_LCP)
1059   {
1060     dst->NdbVersion = dst->BackupVersion;
1061     dst->MySQLVersion = 0;
1062   }
1063 
1064   if(dst->ByteOrder != 0x12345678)
1065     endian = true;
1066 
1067   return true;
1068 }
1069 
1070 bool
readFragHeader(ndbzio_stream * f,BackupFormat::DataFile::FragmentHeader * dst)1071 readFragHeader(ndbzio_stream* f, BackupFormat::DataFile::FragmentHeader * dst){
1072   if(aread(dst, 1, sizeof(* dst), f) != sizeof(* dst))
1073     return false;
1074 
1075   dst->SectionType = ntohl(dst->SectionType);
1076   dst->SectionLength = ntohl(dst->SectionLength);
1077   dst->TableId = ntohl(dst->TableId);
1078   dst->FragmentNo = ntohl(dst->FragmentNo);
1079   dst->ChecksumType = ntohl(dst->ChecksumType);
1080 
1081   if(dst->SectionLength != (sizeof(* dst) >> 2))
1082     RETURN_FALSE();
1083 
1084   if(dst->SectionType != BackupFormat::FRAGMENT_HEADER)
1085     RETURN_FALSE();
1086 
1087   recNo = 0;
1088   recInsert = 0;
1089   recWrite = 0;
1090   recDeleteByRowId = 0;
1091   recDeleteByPageId = 0;
1092 
1093   return true;
1094 }
1095 
1096 bool
readFragFooter(ndbzio_stream * f,BackupFormat::DataFile::FragmentFooter * dst)1097 readFragFooter(ndbzio_stream* f, BackupFormat::DataFile::FragmentFooter * dst){
1098   if(aread(dst, 1, sizeof(* dst), f) != sizeof(* dst))
1099     RETURN_FALSE();
1100 
1101   dst->SectionType = ntohl(dst->SectionType);
1102   dst->SectionLength = ntohl(dst->SectionLength);
1103   dst->TableId = ntohl(dst->TableId);
1104   dst->FragmentNo = ntohl(dst->FragmentNo);
1105   dst->NoOfRecords = ntohl(dst->NoOfRecords);
1106   dst->Checksum = ntohl(dst->Checksum);
1107 
1108   if(dst->SectionLength != (sizeof(* dst) >> 2))
1109     RETURN_FALSE();
1110 
1111   if(dst->SectionType != BackupFormat::FRAGMENT_FOOTER)
1112     RETURN_FALSE();
1113   return true;
1114 }
1115 
1116 
1117 static union {
1118   Uint32 buf[MaxReadWords];
1119   BackupFormat::CtlFile::TableList TableList;
1120   BackupFormat::CtlFile::GCPEntry GcpEntry;
1121   BackupFormat::CtlFile::TableDescription TableDescription;
1122   BackupFormat::LogFile::LogEntry LogEntry;
1123   BackupFormat::LCPCtlFile LCPCtlFile;
1124   char extra_space[4 * BackupFormat::NDB_MAX_LCP_PARTS];
1125 } theData;
1126 
1127 Int32
readRecord(ndbzio_stream * f,Uint32 ** dst,Uint32 * ext_header_type,bool print)1128 readRecord(ndbzio_stream* f, Uint32 **dst, Uint32 *ext_header_type, bool print)
1129 {
1130   Uint32 len;
1131   if(aread(&len, 1, 4, f) != 4)
1132     RETURN_FALSE();
1133 
1134   Uint32 header = ntohl(len);
1135   len = header & 0xFFFF;
1136 
1137   if(aread(theData.buf, 4, len, f) != len)
1138   {
1139     return -1;
1140   }
1141 
1142   if(len > 0)
1143   {
1144     Uint32 header_type = header >> 16;
1145     *ext_header_type = header_type;
1146     if (header_type == BackupFormat::INSERT_TYPE)
1147     {
1148       if (print)
1149       {
1150         ndbout_c("INSERT: RecNo: %u: Len: %x, page(%u,%u)",
1151                  recNo, len, theData.buf[0], theData.buf[1]);
1152         if (num_data_words)
1153         {
1154           ndbout_c("Header_words[Header:%x,GCI:%u,Checksum: %x, X: %x]",
1155                    theData.buf[2],
1156                    theData.buf[3],
1157                    theData.buf[4],
1158                    theData.buf[5]);
1159         }
1160       }
1161       recNo++;
1162       recInsert++;
1163     }
1164     else if (header_type == BackupFormat::WRITE_TYPE)
1165     {
1166       if (print)
1167       {
1168         ndbout_c("WRITE: RecNo: %u: Len: %x, page(%u,%u)",
1169                  recNo, len, theData.buf[0], theData.buf[1]);
1170         if (num_data_words)
1171         {
1172           ndbout_c("Header_words[Header:%x,GCI:%u,Checksum: %x, X: %x]",
1173                    theData.buf[2],
1174                    theData.buf[3],
1175                    theData.buf[4],
1176                    theData.buf[5]);
1177         }
1178       }
1179       recNo++;
1180       recWrite++;
1181     }
1182     else if (header_type == BackupFormat::DELETE_BY_ROWID_TYPE)
1183     {
1184       if (print)
1185         ndbout_c("DELETE_BY_ROWID: RecNo: %u: Len: %x, page(%u,%u)",
1186                  recNo, len, theData.buf[0], theData.buf[1]);
1187       recNo++;
1188       recDeleteByRowId++;
1189     }
1190     else if (header_type == BackupFormat::DELETE_BY_PAGEID_TYPE)
1191     {
1192       if (print)
1193         ndbout_c("DELETE_BY_PAGEID: RecNo: %u: Len: %x, page(%u)",
1194                  recNo, len, theData.buf[0]);
1195       recNo++;
1196       recDeleteByPageId++;
1197     }
1198     else
1199     {
1200       ndbout_c("Wrong header type %u", header_type);
1201     }
1202   }
1203   else
1204   {
1205     ndbout_c("Found %d INSERT records", recInsert);
1206     ndbout_c("Found %d WRITE records", recWrite);
1207     ndbout_c("Found %d DELETE BY ROWID records", recDeleteByRowId);
1208     ndbout_c("Found %d DELETE BY PAGEID records", recDeleteByPageId);
1209     ndbout_c("Found %d IGNOREd records", ignored_rows);
1210     ndbout_c("Found %d records", recNo);
1211     ignored_rows = 0;
1212   }
1213 
1214   * dst = &theData.buf[0];
1215 
1216 
1217   return len;
1218 }
1219 
1220 Int32
readLogEntry(ndbzio_stream * f,Uint32 ** dst,Uint32 file_type,Uint32 version)1221 readLogEntry(ndbzio_stream* f, Uint32 **dst, Uint32 file_type, Uint32 version)
1222 {
1223   static_assert(MaxReadWords >= BackupFormat::LogFile::LogEntry::MAX_SIZE, "");
1224   constexpr Uint32 word_size = sizeof(Uint32);
1225 
1226   Uint32 len;
1227   if(aread(&len, word_size, 1, f) != 1)
1228     RETURN_FALSE();
1229 
1230   len = ntohl(len);
1231 
1232   if (len == 0)
1233     return 0;
1234 
1235   Uint32 data_len;
1236   if (likely(version == 2))
1237   {
1238     constexpr Uint32 header_len =
1239         BackupFormat::LogFile::LogEntry::HEADER_LENGTH_WORDS;
1240     if (len < header_len)
1241     {
1242       return -1;
1243     }
1244     if (1 + len > MaxReadWords)
1245     {
1246       return -1;
1247     }
1248     data_len = len - header_len;
1249     if (aread(&theData.buf[1], word_size, len, f) != len)
1250     {
1251       return -1;
1252     }
1253   }
1254   else
1255   {
1256     assert(version == 1);
1257     constexpr Uint32 header_len =
1258         BackupFormat::LogFile::LogEntry_no_fragid::HEADER_LENGTH_WORDS;
1259     if (len < header_len)
1260     {
1261       return -1;
1262     }
1263     static_assert(header_len <=
1264                     BackupFormat::LogFile::LogEntry::HEADER_LENGTH_WORDS,
1265                   "");
1266     constexpr Uint32 header_len_diff =
1267         BackupFormat::LogFile::LogEntry::HEADER_LENGTH_WORDS - header_len;
1268     if (1 + len + header_len_diff > MaxReadWords)
1269     {
1270       return -1;
1271     }
1272     data_len = len - header_len;
1273     if (aread(&theData.buf[1], word_size, header_len, f) != header_len)
1274     {
1275       return -1;
1276     }
1277     // No fragment id in log event, set it to zero.
1278     theData.buf[BackupFormat::LogFile::LogEntry::FRAGID_OFFSET] = 0;
1279     if (aread(&theData.buf[BackupFormat::LogFile::LogEntry::DATA_OFFSET],
1280               word_size,
1281               data_len,
1282               f) != data_len)
1283     {
1284       return -1;
1285     }
1286   }
1287 
1288   theData.buf[0] = len;
1289 
1290   if(len > 0)
1291     logEntryNo++;
1292 
1293   * dst = &theData.buf[0];
1294 
1295   if (file_type == BackupFormat::UNDO_FILE)
1296   {
1297     Uint32 tail_length;
1298     if (aread(&tail_length, word_size, 1, f) != 1)
1299     {
1300       return -1;
1301     }
1302     tail_length = ntohl(tail_length);
1303 
1304     if (len != tail_length)
1305     {
1306       return -1;
1307     }
1308   }
1309 
1310   return data_len;
1311 }
1312 
1313 NdbOut &
operator <<(NdbOut & ndbout,const BackupFormat::FileHeader & hf)1314 operator<<(NdbOut& ndbout, const BackupFormat::FileHeader & hf){
1315 
1316   char buf[9];
1317   memcpy(buf, hf.Magic, sizeof(hf.Magic));
1318   buf[8] = 0;
1319 
1320   ndbout << "-- FileHeader:" << endl;
1321   ndbout << "Magic: " << buf << endl;
1322   ndbout << "BackupVersion: " << hex << hf.BackupVersion << endl;
1323   ndbout << "SectionType: " << hf.SectionType << endl;
1324   ndbout << "SectionLength: " << hf.SectionLength << endl;
1325   ndbout << "FileType: " << hf.FileType << endl;
1326   ndbout << "BackupId: " << hf.BackupId << endl;
1327   ndbout << "BackupKey: [ " << hex << hf.BackupKey_0
1328 	 << " "<< hf.BackupKey_1 << " ]" << endl;
1329   ndbout << "ByteOrder: " << hex << hf.ByteOrder << endl;
1330   return ndbout;
1331 }
1332 
operator <<(NdbOut & ndbout,const BackupFormat::DataFile::FragmentHeader & hf)1333 NdbOut & operator<<(NdbOut& ndbout,
1334 		    const BackupFormat::DataFile::FragmentHeader & hf){
1335 
1336   ndbout << "-- Fragment header:" << endl;
1337   ndbout << "SectionType: " << hf.SectionType << endl;
1338   ndbout << "SectionLength: " << hf.SectionLength << endl;
1339   ndbout << "TableId: " << hf.TableId << endl;
1340   ndbout << "FragmentNo: " << hf.FragmentNo << endl;
1341   ndbout << "ChecksumType: " << hf.ChecksumType << endl;
1342 
1343   return ndbout;
1344 }
1345 
operator <<(NdbOut & ndbout,const BackupFormat::DataFile::FragmentFooter & hf)1346 NdbOut & operator<<(NdbOut& ndbout,
1347                     const BackupFormat::DataFile::FragmentFooter & hf){
1348 
1349   ndbout << "-- Fragment footer:" << endl;
1350   ndbout << "SectionType: " << hf.SectionType << endl;
1351   ndbout << "SectionLength: " << hf.SectionLength << endl;
1352   ndbout << "TableId: " << hf.TableId << endl;
1353   ndbout << "FragmentNo: " << hf.FragmentNo << endl;
1354   ndbout << "NoOfRecords: " << hf.NoOfRecords << endl;
1355   ndbout << "Checksum: " << hf.Checksum << endl;
1356 
1357   return ndbout;
1358 }
1359 
operator <<(NdbOut & ndbout,const BackupFormat::LCPCtlFile & lcf)1360 NdbOut & operator<<(NdbOut& ndbout,
1361                    const BackupFormat::LCPCtlFile & lcf)
1362 {
1363   ndbout << "-- LCP Control file part:" << endl;
1364   ndbout << "Checksum: " << hex << lcf.Checksum << endl;
1365   ndbout << "ValidFlag: " << lcf.ValidFlag << endl;
1366   ndbout << "TableId: " << lcf.TableId << endl;
1367   ndbout << "FragmentId: " << lcf.FragmentId << endl;
1368   ndbout << "CreateTableVersion: " << lcf.CreateTableVersion << endl;
1369   ndbout << "CreateGci: " << lcf.CreateGci << endl;
1370   ndbout << "MaxGciCompleted: " << lcf.MaxGciCompleted << endl;
1371   ndbout << "MaxGciWritten: " << lcf.MaxGciWritten << endl;
1372   ndbout << "LcpId: " << lcf.LcpId << endl;
1373   ndbout << "LocalLcpId: " << lcf.LocalLcpId << endl;
1374   ndbout << "MaxPageCount: " << lcf.MaxPageCount << endl;
1375   ndbout << "MaxNumberDataFiles: " << lcf.MaxNumberDataFiles << endl;
1376   ndbout << "LastDataFileNumber: " << lcf.LastDataFileNumber << endl;
1377   ndbout << "RowCount: " <<
1378             Uint64(Uint64(lcf.RowCountLow) +
1379                    (Uint64(lcf.RowCountHigh) << 32)) << endl;
1380   ndbout << "MaxPartPairs: " << lcf.MaxPartPairs << endl;
1381   ndbout << "NumPartPairs: " << lcf.NumPartPairs << endl;
1382   if (lcf.NumPartPairs > BackupFormat::NDB_MAX_LCP_PARTS)
1383   {
1384     ndbout_c("Too many parts");
1385     abort();
1386   }
1387   for (Uint32 i = 0; i < lcf.NumPartPairs; i++)
1388   {
1389     ndbout << "Pair[" << i << "]: StartPart: "
1390            << lcf.partPairs[i].startPart << " NumParts: "
1391            << lcf.partPairs[i].numParts << endl;
1392   }
1393   return ndbout;
1394 }
1395 
decompress_part_pairs(struct BackupFormat::LCPCtlFile * lcpCtlFilePtr,Uint32 num_parts)1396 Uint32 decompress_part_pairs(
1397   struct BackupFormat::LCPCtlFile *lcpCtlFilePtr,
1398   Uint32 num_parts)
1399 {
1400   static unsigned char c_part_array[BackupFormat::NDB_MAX_LCP_PARTS * 4];
1401   Uint32 total_parts = 0;
1402   unsigned char *part_array = (unsigned char*)&lcpCtlFilePtr->partPairs[0].startPart;
1403   memcpy(c_part_array, part_array, 3 * num_parts);
1404   Uint32 j = 0;
1405   for (Uint32 part = 0; part < num_parts; part++)
1406   {
1407     Uint32 part_0 = c_part_array[j+0];
1408     Uint32 part_1 = c_part_array[j+1];
1409     Uint32 part_2 = c_part_array[j+2];
1410     Uint32 startPart = ((part_1 & 0xF) + (part_0 << 4));
1411     Uint32 numParts = (((part_1 >> 4) & 0xF)) + (part_2 << 4);
1412     lcpCtlFilePtr->partPairs[part].startPart = startPart;
1413     lcpCtlFilePtr->partPairs[part].numParts = numParts;
1414     total_parts += numParts;
1415     j += 3;
1416   }
1417   return total_parts;
1418 }
1419 
1420 bool
readLCPCtlFile(ndbzio_stream * f,BackupFormat::LCPCtlFile * ret)1421 readLCPCtlFile(ndbzio_stream* f, BackupFormat::LCPCtlFile *ret)
1422 {
1423   char * struct_dst = (char*)&theData.LCPCtlFile.Checksum;
1424   size_t struct_sz = sizeof(BackupFormat::LCPCtlFile) -
1425               sizeof(BackupFormat::FileHeader);
1426 
1427   if(aread(struct_dst, (struct_sz - 4), 1, f) != 1)
1428     RETURN_FALSE();
1429 
1430   theData.LCPCtlFile.Checksum = ntohl(theData.LCPCtlFile.Checksum);
1431   theData.LCPCtlFile.ValidFlag = ntohl(theData.LCPCtlFile.ValidFlag);
1432   theData.LCPCtlFile.TableId = ntohl(theData.LCPCtlFile.TableId);
1433   theData.LCPCtlFile.FragmentId = ntohl(theData.LCPCtlFile.FragmentId);
1434   theData.LCPCtlFile.CreateTableVersion =
1435     ntohl(theData.LCPCtlFile.CreateTableVersion);
1436   theData.LCPCtlFile.CreateGci = ntohl(theData.LCPCtlFile.CreateGci);
1437   theData.LCPCtlFile.MaxGciCompleted =
1438     ntohl(theData.LCPCtlFile.MaxGciCompleted);
1439   theData.LCPCtlFile.MaxGciWritten =
1440     ntohl(theData.LCPCtlFile.MaxGciWritten);
1441   theData.LCPCtlFile.LcpId = ntohl(theData.LCPCtlFile.LcpId);
1442   theData.LCPCtlFile.LocalLcpId = ntohl(theData.LCPCtlFile.LocalLcpId);
1443   theData.LCPCtlFile.MaxPageCount = ntohl(theData.LCPCtlFile.MaxPageCount);
1444   theData.LCPCtlFile.MaxNumberDataFiles =
1445     ntohl(theData.LCPCtlFile.MaxNumberDataFiles);
1446   theData.LCPCtlFile.LastDataFileNumber =
1447     ntohl(theData.LCPCtlFile.LastDataFileNumber);
1448   theData.LCPCtlFile.RowCountLow = ntohl(theData.LCPCtlFile.RowCountLow);
1449   theData.LCPCtlFile.RowCountHigh = ntohl(theData.LCPCtlFile.RowCountHigh);
1450   theData.LCPCtlFile.MaxPartPairs = ntohl(theData.LCPCtlFile.MaxPartPairs);
1451   theData.LCPCtlFile.NumPartPairs = ntohl(theData.LCPCtlFile.NumPartPairs);
1452 
1453   size_t parts = theData.LCPCtlFile.NumPartPairs;
1454   char * part_dst = (char*)&theData.LCPCtlFile.partPairs[0];
1455   if(aread(part_dst, 3 * parts, 1, f) != 1)
1456     RETURN_FALSE();
1457 
1458   decompress_part_pairs(&theData.LCPCtlFile, theData.LCPCtlFile.NumPartPairs);
1459   size_t file_header_sz = sizeof(BackupFormat::FileHeader);
1460   size_t copy_sz = struct_sz + (4 * parts) + file_header_sz;
1461   memcpy((char*)ret, &theData.LCPCtlFile, copy_sz);
1462   return true;
1463 }
1464 
1465 bool
readTableList(ndbzio_stream * f,BackupFormat::CtlFile::TableList ** ret)1466 readTableList(ndbzio_stream* f, BackupFormat::CtlFile::TableList **ret){
1467   BackupFormat::CtlFile::TableList * dst = &theData.TableList;
1468 
1469   if(aread(dst, 4, 2, f) != 2)
1470     RETURN_FALSE();
1471 
1472   dst->SectionType = ntohl(dst->SectionType);
1473   dst->SectionLength = ntohl(dst->SectionLength);
1474 
1475   if(dst->SectionType != BackupFormat::TABLE_LIST)
1476     RETURN_FALSE();
1477 
1478   const Uint32 len = dst->SectionLength - 2;
1479   if(aread(&dst->TableIds[0], 4, len, f) != len)
1480     RETURN_FALSE();
1481 
1482   for(Uint32 i = 0; i<len; i++){
1483     dst->TableIds[i] = ntohl(dst->TableIds[i]);
1484   }
1485 
1486   * ret = dst;
1487 
1488   return true;
1489 }
1490 
1491 bool
readTableDesc(ndbzio_stream * f,BackupFormat::CtlFile::TableDescription ** ret)1492 readTableDesc(ndbzio_stream* f, BackupFormat::CtlFile::TableDescription **ret){
1493   BackupFormat::CtlFile::TableDescription * dst = &theData.TableDescription;
1494 
1495   if(aread(dst, 4, 3, f) != 3)
1496     RETURN_FALSE();
1497 
1498   dst->SectionType = ntohl(dst->SectionType);
1499   dst->SectionLength = ntohl(dst->SectionLength);
1500   dst->TableType = ntohl(dst->TableType);
1501 
1502   if(dst->SectionType != BackupFormat::TABLE_DESCRIPTION)
1503     RETURN_FALSE();
1504 
1505   const Uint32 len = dst->SectionLength - 3;
1506   if(aread(&dst->DictTabInfo[0], 4, len, f) != len)
1507     RETURN_FALSE();
1508 
1509   * ret = dst;
1510 
1511   return true;
1512 }
1513 
1514 bool
readGCPEntry(ndbzio_stream * f,BackupFormat::CtlFile::GCPEntry ** ret)1515 readGCPEntry(ndbzio_stream* f, BackupFormat::CtlFile::GCPEntry **ret){
1516   BackupFormat::CtlFile::GCPEntry * dst = &theData.GcpEntry;
1517 
1518   if(aread(dst, 4, 4, f) != 4)
1519     RETURN_FALSE();
1520 
1521   dst->SectionType = ntohl(dst->SectionType);
1522   dst->SectionLength = ntohl(dst->SectionLength);
1523 
1524   if(dst->SectionType != BackupFormat::GCP_ENTRY)
1525     RETURN_FALSE();
1526 
1527   dst->StartGCP = ntohl(dst->StartGCP);
1528   dst->StopGCP = ntohl(dst->StopGCP);
1529 
1530   * ret = dst;
1531 
1532   return true;
1533 }
1534 
1535 
1536 NdbOut &
operator <<(NdbOut & ndbout,const BackupFormat::CtlFile::TableList & hf)1537 operator<<(NdbOut& ndbout, const BackupFormat::CtlFile::TableList & hf) {
1538   ndbout << "-- Table List:" << endl;
1539   ndbout << "SectionType: " << hf.SectionType << endl;
1540   ndbout << "SectionLength: " << hf.SectionLength << endl;
1541   ndbout << "Tables: ";
1542   for(Uint32 i = 0; i < hf.SectionLength - 2; i++){
1543     ndbout << hf.TableIds[i] << " ";
1544     if((i + 1) % 16 == 0)
1545       ndbout << endl;
1546   }
1547   ndbout << endl;
1548   return ndbout;
1549 }
1550 
1551 NdbOut &
operator <<(NdbOut & ndbout,const BackupFormat::CtlFile::TableDescription & hf)1552 operator<<(NdbOut& ndbout, const BackupFormat::CtlFile::TableDescription & hf){
1553   ndbout << "-- Table Description:" << endl;
1554   ndbout << "SectionType: " << hf.SectionType << endl;
1555   ndbout << "SectionLength: " << hf.SectionLength << endl;
1556   ndbout << "TableType: " << hf.TableType << endl;
1557 
1558   SimplePropertiesLinearReader it(&hf.DictTabInfo[0],  hf.SectionLength - 3);
1559   char buf[1024];
1560   for(it.first(); it.valid(); it.next()){
1561     switch(it.getValueType()){
1562     case SimpleProperties::Uint32Value:
1563       ndbout << "Key: " << it.getKey()
1564 	     << " value(" << it.getValueLen() << ") : "
1565 	     << it.getUint32() << endl;
1566       break;
1567     case SimpleProperties::StringValue:
1568       if(it.getValueLen() < sizeof(buf)){
1569 	it.getString(buf);
1570 	ndbout << "Key: " << it.getKey()
1571 	       << " value(" << it.getValueLen() << ") : "
1572 	       << "\"" << buf << "\"" << endl;
1573       } else {
1574 	ndbout << "Key: " << it.getKey()
1575 	       << " value(" << it.getValueLen() << ") : "
1576 	       << "\"" << "<TOO LONG>" << "\"" << endl;
1577 
1578       }
1579       break;
1580     case SimpleProperties::BinaryValue:
1581       if(it.getValueLen() < sizeof(buf))
1582       {
1583 	ndbout << "Key: " << it.getKey()
1584 	       << " binary value len = " << it.getValueLen() << endl;
1585 
1586       }
1587       else
1588       {
1589 	ndbout << "Key: " << it.getKey()
1590 	       << " value(" << it.getValueLen() << ") : "
1591 	       << "\"" << "<TOO LONG>" << "\"" << endl;
1592       }
1593       break;
1594     default:
1595       ndbout << "Unknown type for key: " << it.getKey()
1596 	     << " type: " << it.getValueType() << endl;
1597     }
1598   }
1599 
1600   return ndbout;
1601 }
1602 
1603 NdbOut &
operator <<(NdbOut & ndbout,const BackupFormat::CtlFile::GCPEntry & hf)1604 operator<<(NdbOut& ndbout, const BackupFormat::CtlFile::GCPEntry & hf) {
1605   ndbout << "-- GCP Entry:" << endl;
1606   ndbout << "SectionType: " << hf.SectionType << endl;
1607   ndbout << "SectionLength: " << hf.SectionLength << endl;
1608   ndbout << "Start GCP: " << hf.StartGCP << endl;
1609   ndbout << "Stop GCP: " << hf.StopGCP << endl;
1610 
1611   return ndbout;
1612 }
1613 
1614