Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / third_party / sqlite / src / tool / restore_jrnl.tcl
1 # 2010 January 7
2 #
3 # The author disclaims copyright to this source code.  In place of
4 # a legal notice, here is a blessing:
5 #
6 #    May you do good and not evil.
7 #    May you find forgiveness for yourself and forgive others.
8 #    May you share freely, never taking more than you give.
9 #
10 #***********************************************************************
11 # This file implements utility functions for SQLite library.
12 #
13 # This file attempts to restore the header of a journal.
14 # This may be useful for rolling-back the last committed 
15 # transaction from a recovered journal.
16 #
17
18 package require sqlite3
19
20 set parm_error 0
21 set fix_chksums 0
22 set dump_pages 0
23 set db_name ""
24
25 for {set i 0} {$i<$argc} {incr i} {
26   if {[lindex $argv $i] == "-fix_chksums"} {
27     set fix_chksums -1
28   } elseif {[lindex $argv $i] == "-dump_pages"} {
29     set dump_pages -1
30   } elseif {$db_name == ""} {
31     set db_name [lindex $argv $i]
32     set jrnl_name $db_name-journal
33   } else {
34     set parm_error -1
35   }
36 }
37 if {$parm_error || $db_name == ""} {
38   puts "USAGE: restore_jrnl.tcl \[-fix_chksums\] \[-dump_pages\] db_name"
39   puts "Example: restore_jrnl.tcl foo.sqlite"
40   return
41 }
42
43 # is there a way to determine this?
44 set sectsz 512
45
46 # Copy file $from into $to
47 #
48 proc copy_file {from to} {
49   file copy -force $from $to
50 }
51
52 # Execute some SQL
53 #
54 proc catchsql {sql} {
55   set rc [catch {uplevel [list db eval $sql]} msg]
56   list $rc $msg
57 }
58
59 # Perform a test
60 #
61 proc do_test {name cmd expected} {
62   puts -nonewline "$name ..."
63   set res [uplevel $cmd]
64   if {$res eq $expected} {
65     puts Ok
66   } else {
67     puts Error
68     puts "  Got: $res"
69     puts "  Expected: $expected"
70   }
71 }
72
73 # Calc checksum nonce from journal page data.
74 #
75 proc calc_nonce {jrnl_pgno} {
76   global sectsz
77   global db_pgsz
78   global jrnl_name
79   set jrnl_pg_offset [expr $sectsz+((4+$db_pgsz+4)*$jrnl_pgno)]
80   set nonce [hexio_get_int [hexio_read $jrnl_name [expr $jrnl_pg_offset+4+$db_pgsz] 4]]
81   for {set i [expr $db_pgsz-200]} {$i>0} {set i [expr $i-200]} {
82     set byte [hexio_get_int [hexio_read $jrnl_name [expr $jrnl_pg_offset+4+$i] 1]]
83     set nonce [expr $nonce-$byte]
84   }
85   return $nonce
86 }
87
88 # Calc checksum from journal page data.
89 #
90 proc calc_chksum {jrnl_pgno} {
91   global sectsz
92   global db_pgsz
93   global jrnl_name
94   global nonce
95   set jrnl_pg_offset [expr $sectsz+((4+$db_pgsz+4)*$jrnl_pgno)]
96   set chksum $nonce
97   for {set i [expr $db_pgsz-200]} {$i>0} {set i [expr $i-200]} {
98     set byte [hexio_get_int [hexio_read $jrnl_name [expr $jrnl_pg_offset+4+$i] 1]]
99     set chksum [expr $chksum+$byte]
100   }
101   return $chksum
102 }
103
104 # Print journal page data in hex dump form
105 #
106 proc dump_jrnl_page {jrnl_pgno} {
107   global sectsz
108   global db_pgsz
109   global jrnl_name
110
111   # print a header block for the page
112   puts [string repeat "-" 79]
113   set jrnl_pg_offset [expr $sectsz+((4+$db_pgsz+4)*$jrnl_pgno)]
114   set db_pgno [hexio_get_int [hexio_read $jrnl_name [expr $jrnl_pg_offset] 4]]
115   set chksum [hexio_get_int [hexio_read $jrnl_name [expr $jrnl_pg_offset+4+$db_pgsz] 4]]
116   set nonce [calc_nonce $jrnl_pgno]
117   puts [ format {jrnl_pg_offset: %08x (%d)  jrnl_pgno: %d  db_pgno: %d} \\r
118       $jrnl_pg_offset $jrnl_pg_offset \\r
119       $jrnl_pgno $db_pgno]\r
120   puts [ format {nonce: %08x chksum: %08x} \\r
121       $nonce $chksum]\r
122
123   # now hex dump the data
124   # This is derived from the Tcler's WIKI\r
125   set fid [open $jrnl_name r]\r
126   fconfigure $fid -translation binary -encoding binary\r
127   seek $fid [expr $jrnl_pg_offset+4]\r
128   set data [read $fid $db_pgsz]\r
129   close $fid\r
130   for {set addr 0} {$addr<$db_pgsz} {set addr [expr $addr+16]} {
131     # get 16 bytes of data\r
132     set s [string range $data $addr [expr $addr+16]]\r
133     \r
134     # Convert the data to hex and to characters.\r
135     binary scan $s H*@0a* hex ascii\r
136 \r
137     # Replace non-printing characters in the data.\r
138     regsub -all -- {[^[:graph:] ]} $ascii {.} ascii\r
139 \r
140     # Split the 16 bytes into two 8-byte chunks\r
141     regexp -- {(.{16})(.{0,16})} $hex -> hex1 hex2\r
142 \r
143     # Convert the hex to pairs of hex digits\r
144     regsub -all -- {..} $hex1 {& } hex1\r
145     regsub -all -- {..} $hex2 {& } hex2\r
146 \r
147     # Print the hex and ascii data\r
148     puts [ format {%08x %-24s %-24s %-16s} \\r
149         $addr $hex1 $hex2 $ascii ]\r
150   }\r
151 }
152
153 # Setup for the tests.  Make a backup copy of the files.
154 #
155 if [file exist $db_name.org] {
156   puts "ERROR: during back-up: $db_name.org exists already."
157   return;
158 }
159 if [file exist $jrnl_name.org] {
160   puts "ERROR: during back-up: $jrnl_name.org exists already."
161   return
162 }
163 copy_file $db_name $db_name.org
164 copy_file $jrnl_name $jrnl_name.org
165
166 set db_fsize [file size $db_name]
167 set db_pgsz [hexio_get_int [hexio_read $db_name 16 2]]
168 set db_npage [expr {$db_fsize / $db_pgsz}]
169
170 set jrnl_fsize [file size $jrnl_name]
171 set jrnl_npage [expr {($jrnl_fsize - $sectsz) / (4 + $db_pgsz + 4)}]
172
173 # calculate checksum nonce for first page
174 set nonce [calc_nonce 0]
175
176 # verify all the pages in the journal use the same nonce
177 for {set i 1} {$i<$jrnl_npage} {incr i} {
178   set tnonce [calc_nonce $i]
179   if {$tnonce != $nonce} {
180     puts "WARNING: different nonces: 0=$nonce $i=$tnonce"
181     if {$fix_chksums } {
182       set jrnl_pg_offset [expr $sectsz+((4+$db_pgsz+4)*$i)]
183       set tchksum [calc_chksum $i]
184       hexio_write $jrnl_name [expr $jrnl_pg_offset+4+$db_pgsz] [format %08x $tchksum]
185       puts "INFO: fixing chksum: $i=$tchksum"
186     }
187   }
188 }
189
190 # verify all the page numbers in the journal
191 for {set i 0} {$i<$jrnl_npage} {incr i} {
192   set jrnl_pg_offset [expr $sectsz+((4+$db_pgsz+4)*$i)]
193   set db_pgno [hexio_get_int [hexio_read $jrnl_name $jrnl_pg_offset 4]]
194   if {$db_pgno < 1} {
195     puts "WARNING: page number < 1: $i=$db_pgno"
196   }
197   if {$db_pgno >= $db_npage} {
198     puts "WARNING: page number >= $db_npage: $i=$db_pgno"
199   }
200 }
201
202 # dump page data
203 if {$dump_pages} {
204   for {set i 0} {$i<$jrnl_npage} {incr i} {
205     dump_jrnl_page $i
206   }
207 }
208
209 # write the 8 byte magic string
210 hexio_write $jrnl_name 0 d9d505f920a163d7
211
212 # write -1 for number of records
213 hexio_write $jrnl_name 8 ffffffff
214
215 # write 00 for checksum nonce
216 hexio_write $jrnl_name 12 [format %08x $nonce]
217
218 # write page count
219 hexio_write $jrnl_name 16 [format %08x $db_npage]
220
221 # write sector size
222 hexio_write $jrnl_name 20 [format %08x $sectsz]
223
224 # write page size
225 hexio_write $jrnl_name 24 [format %08x $db_pgsz]
226
227 # check the integrity of the database with the patched journal
228 sqlite3 db $db_name
229 do_test restore_jrnl-1.0 {
230   catchsql {PRAGMA integrity_check}
231 } {0 ok}
232 db close
233