2 <html xmlns=
"http://www.w3.org/1999/xhtml" lang=
"en">
4 <meta charset=
"UTF-8"/>
5 <meta http-equiv=
"X-UA-Compatible" content=
"IE=edge"/>
6 <meta name=
"viewport" content=
"width=device-width, initial-scale=1.0"/>
7 <meta name=
"generator" content=
"Asciidoctor 2.0.20"/>
8 <title>How to recover an object from scratch
</title>
9 <link rel=
"stylesheet" href=
"https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"/>
11 /*! Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */
12 /* Uncomment the following line when using as a custom stylesheet */
13 /* @import
"https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"; */
14 html{font-family:sans-serif;-webkit-text-size-adjust:
100%}
16 a:focus{outline:thin dotted}
17 a:active,a:hover{outline:
0}
18 h1{font-size:
2em;margin:
.67em
0}
19 b,strong{font-weight:bold}
21 abbr[title]{cursor:help;border-bottom:
1px dotted #dddddf;text-decoration:none}
22 dfn{font-style:italic}
24 mark{background:#ff0;color:#
000}
25 code,kbd,pre,samp{font-family:monospace;font-size:
1em}
26 pre{white-space:pre-wrap}
27 q{quotes:
"\201C" "\201D" "\2018" "\2019"}
29 sub,sup{font-size:
75%;line-height:
0;position:relative;vertical-align:baseline}
33 svg:not(:root){overflow:hidden}
35 audio,video{display:inline-block}
36 audio:not([controls]){display:none;height:
0}
37 fieldset{border:
1px solid silver;margin:
0 2px;padding:
.35em
.625em
.75em}
38 legend{border:
0;padding:
0}
39 button,input,select,textarea{font-family:inherit;font-size:
100%;margin:
0}
40 button,input{line-height:normal}
41 button,select{text-transform:none}
42 button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}
43 button[disabled],html input[disabled]{cursor:default}
44 input[type=checkbox],input[type=radio]{padding:
0}
45 button::-moz-focus-inner,input::-moz-focus-inner{border:
0;padding:
0}
46 textarea{overflow:auto;vertical-align:top}
47 table{border-collapse:collapse;border-spacing:
0}
48 *,::before,::after{box-sizing:border-box}
49 html,body{font-size:
100%}
50 body{background:#fff;color:rgba(
0,
0,
0,
.8);padding:
0;margin:
0;font-family:
"Noto Serif",
"DejaVu Serif",serif;line-height:
1;position:relative;cursor:auto;-moz-tab-size:
4;-o-tab-size:
4;tab-size:
4;word-wrap:anywhere;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
51 a:hover{cursor:pointer}
52 img,object,embed{max-width:
100%;height:auto}
53 object,embed{height:
100%}
54 img{-ms-interpolation-mode:bicubic}
55 .left{float:left!important}
56 .right{float:right!important}
57 .text-left{text-align:left!important}
58 .text-right{text-align:right!important}
59 .text-center{text-align:center!important}
60 .text-justify{text-align:justify!important}
62 img,object,svg{display:inline-block;vertical-align:middle}
63 textarea{height:auto;min-height:
50px}
65 .subheader,.admonitionblock td.content
>.title,.audioblock
>.title,.exampleblock
>.title,.imageblock
>.title,.listingblock
>.title,.literalblock
>.title,.stemblock
>.title,.openblock
>.title,.paragraph
>.title,.quoteblock
>.title,table.tableblock
>.title,.verseblock
>.title,.videoblock
>.title,.dlist
>.title,.olist
>.title,.ulist
>.title,.qlist
>.title,.hdlist
>.title{line-height:
1.45;color:#
7a2518;font-weight:
400;margin-top:
0;margin-bottom:
.25em}
66 div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock
>.content
>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:
0;padding:
0}
67 a{color:#
2156a5;text-decoration:underline;line-height:inherit}
68 a:hover,a:focus{color:#
1d4b8f}
70 p{line-height:
1.6;margin-bottom:
1.25em;text-rendering:optimizeLegibility}
71 p aside{font-size:
.875em;line-height:
1.35;font-style:italic}
72 h1,h2,h3,#toctitle,.sidebarblock
>.content
>.title,h4,h5,h6{font-family:
"Open Sans",
"DejaVu Sans",sans-serif;font-weight:
300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:
1em;margin-bottom:
.5em;line-height:
1.0125em}
73 h1 small,h2 small,h3 small,#toctitle small,.sidebarblock
>.content
>.title small,h4 small,h5 small,h6 small{font-size:
60%;color:#e99b8f;line-height:
0}
75 h2{font-size:
1.6875em}
76 h3,#toctitle,.sidebarblock
>.content
>.title{font-size:
1.375em}
77 h4,h5{font-size:
1.125em}
79 hr{border:solid #dddddf;border-width:
1px
0 0;clear:both;margin:
1.25em
0 1.1875em}
80 em,i{font-style:italic;line-height:inherit}
81 strong,b{font-weight:bold;line-height:inherit}
82 small{font-size:
60%;line-height:inherit}
83 code{font-family:
"Droid Sans Mono",
"DejaVu Sans Mono",monospace;font-weight:
400;color:rgba(
0,
0,
0,
.9)}
84 ul,ol,dl{line-height:
1.6;margin-bottom:
1.25em;list-style-position:outside;font-family:inherit}
85 ul,ol{margin-left:
1.5em}
86 ul li ul,ul li ol{margin-left:
1.25em;margin-bottom:
0}
87 ul.circle{list-style-type:circle}
88 ul.disc{list-style-type:disc}
89 ul.square{list-style-type:square}
90 ul.circle ul:not([class]),ul.disc ul:not([class]),ul.square ul:not([class]){list-style:inherit}
91 ol li ul,ol li ol{margin-left:
1.25em;margin-bottom:
0}
92 dl dt{margin-bottom:
.3125em;font-weight:bold}
93 dl dd{margin-bottom:
1.25em}
94 blockquote{margin:
0 0 1.25em;padding:
.5625em
1.25em
0 1.1875em;border-left:
1px solid #ddd}
95 blockquote,blockquote p{line-height:
1.6;color:rgba(
0,
0,
0,
.85)}
96 @media screen and (min-width:
768px){h1,h2,h3,#toctitle,.sidebarblock
>.content
>.title,h4,h5,h6{line-height:
1.2}
98 h2{font-size:
2.3125em}
99 h3,#toctitle,.sidebarblock
>.content
>.title{font-size:
1.6875em}
100 h4{font-size:
1.4375em}}
101 table{background:#fff;margin-bottom:
1.25em;border:
1px solid #dedede;word-wrap:normal}
102 table thead,table tfoot{background:#f7f8f7}
103 table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:
.5em
.625em
.625em;font-size:inherit;color:rgba(
0,
0,
0,
.8);text-align:left}
104 table tr th,table tr td{padding:
.5625em
.625em;font-size:inherit;color:rgba(
0,
0,
0,
.8)}
105 table tr.even,table tr.alt{background:#f8f8f7}
106 table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{line-height:
1.6}
107 h1,h2,h3,#toctitle,.sidebarblock
>.content
>.title,h4,h5,h6{line-height:
1.2;word-spacing:-
.05em}
108 h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock
>.content
>.title strong,h4 strong,h5 strong,h6 strong{font-weight:
400}
109 .center{margin-left:auto;margin-right:auto}
111 .clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:
" ";display:table}
112 .clearfix::after,.float-group::after{clear:both}
113 :not(pre).nobreak{word-wrap:normal}
114 :not(pre).nowrap{white-space:nowrap}
115 :not(pre).pre-wrap{white-space:pre-wrap}
116 :not(pre):not([class^=L])
>code{font-size:
.9375em;font-style:normal!important;letter-spacing:
0;padding:
.1em
.5ex;word-spacing:-
.15em;background:#f7f7f8;border-radius:
4px;line-height:
1.45;text-rendering:optimizeSpeed}
117 pre{color:rgba(
0,
0,
0,
.9);font-family:
"Droid Sans Mono",
"DejaVu Sans Mono",monospace;line-height:
1.45;text-rendering:optimizeSpeed}
118 pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit}
119 pre
>code{display:block}
120 pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal}
121 em em{font-style:normal}
122 strong strong{font-weight:
400}
123 .keyseq{color:rgba(
51,
51,
51,
.8)}
124 kbd{font-family:
"Droid Sans Mono",
"DejaVu Sans Mono",monospace;display:inline-block;color:rgba(
0,
0,
0,
.8);font-size:
.65em;line-height:
1.45;background:#f7f7f7;border:
1px solid #ccc;border-radius:
3px;box-shadow:
0 1px
0 rgba(
0,
0,
0,
.2),inset
0 0 0 .1em #fff;margin:
0 .15em;padding:
.2em
.5em;vertical-align:middle;position:relative;top:-
.1em;white-space:nowrap}
125 .keyseq kbd:first-child{margin-left:
0}
126 .keyseq kbd:last-child{margin-right:
0}
127 .menuseq,.menuref{color:#
000}
128 .menuseq b:not(.caret),.menuref{font-weight:inherit}
129 .menuseq{word-spacing:-
.02em}
130 .menuseq b.caret{font-size:
1.25em;line-height:
.8}
131 .menuseq i.caret{font-weight:bold;text-align:center;width:
.45em}
132 b.button::before,b.button::after{position:relative;top:-
1px;font-weight:
400}
133 b.button::before{content:
"[";padding:
0 3px
0 2px}
134 b.button::after{content:
"]";padding:
0 2px
0 3px}
135 p a
>code:hover{color:rgba(
0,
0,
0,
.9)}
136 #header,#content,#footnotes,#footer{width:
100%;margin:
0 auto;max-width:
62.5em;*zoom:
1;position:relative;padding-left:
.9375em;padding-right:
.9375em}
137 #header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:
" ";display:table}
138 #header::after,#content::after,#footnotes::after,#footer::after{clear:both}
139 #content{margin-top:
1.25em}
140 #content::before{content:none}
141 #header
>h1:first-child{color:rgba(
0,
0,
0,
.85);margin-top:
2.25rem;margin-bottom:
0}
142 #header
>h1:first-child+#toc{margin-top:
8px;border-top:
1px solid #dddddf}
143 #header
>h1:only-child,body.toc2 #header
>h1:nth-last-child(
2){border-bottom:
1px solid #dddddf;padding-bottom:
8px}
144 #header .details{border-bottom:
1px solid #dddddf;line-height:
1.45;padding-top:
.25em;padding-bottom:
.25em;padding-left:
.25em;color:rgba(
0,
0,
0,
.6);display:flex;flex-flow:row wrap}
145 #header .details span:first-child{margin-left:-
.125em}
146 #header .details span.email a{color:rgba(
0,
0,
0,
.85)}
147 #header .details br{display:none}
148 #header .details br+span::before{content:
"\00a0\2013\00a0"}
149 #header .details br+span.author::before{content:
"\00a0\22c5\00a0";color:rgba(
0,
0,
0,
.85)}
150 #header .details br+span#revremark::before{content:
"\00a0|\00a0"}
151 #header #revnumber{text-transform:capitalize}
152 #header #revnumber::after{content:
"\00a0"}
153 #content
>h1:first-child:not([class]){color:rgba(
0,
0,
0,
.85);border-bottom:
1px solid #dddddf;padding-bottom:
8px;margin-top:
0;padding-top:
1rem;margin-bottom:
1.25rem}
154 #toc{border-bottom:
1px solid #e7e7e9;padding-bottom:
.5em}
155 #toc
>ul{margin-left:
.125em}
156 #toc ul.sectlevel0
>li
>a{font-style:italic}
157 #toc ul.sectlevel0 ul.sectlevel1{margin:
.5em
0}
158 #toc ul{font-family:
"Open Sans",
"DejaVu Sans",sans-serif;list-style-type:none}
159 #toc li{line-height:
1.3334;margin-top:
.3334em}
160 #toc a{text-decoration:none}
161 #toc a:active{text-decoration:underline}
162 #toctitle{color:#
7a2518;font-size:
1.2em}
163 @media screen and (min-width:
768px){#toctitle{font-size:
1.375em}
164 body.toc2{padding-left:
15em;padding-right:
0}
165 #toc.toc2{margin-top:
0!important;background:#f8f8f7;position:fixed;width:
15em;left:
0;top:
0;border-right:
1px solid #e7e7e9;border-top-width:
0!important;border-bottom-width:
0!important;z-index:
1000;padding:
1.25em
1em;height:
100%;overflow:auto}
166 #toc.toc2 #toctitle{margin-top:
0;margin-bottom:
.8rem;font-size:
1.2em}
167 #toc.toc2
>ul{font-size:
.9em;margin-bottom:
0}
168 #toc.toc2 ul ul{margin-left:
0;padding-left:
1em}
169 #toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:
0;margin-top:
.5em;margin-bottom:
.5em}
170 body.toc2.toc-right{padding-left:
0;padding-right:
15em}
171 body.toc2.toc-right #toc.toc2{border-right-width:
0;border-left:
1px solid #e7e7e9;left:auto;right:
0}}
172 @media screen and (min-width:
1280px){body.toc2{padding-left:
20em;padding-right:
0}
173 #toc.toc2{width:
20em}
174 #toc.toc2 #toctitle{font-size:
1.375em}
175 #toc.toc2
>ul{font-size:
.95em}
176 #toc.toc2 ul ul{padding-left:
1.25em}
177 body.toc2.toc-right{padding-left:
0;padding-right:
20em}}
178 #content #toc{border:
1px solid #e0e0dc;margin-bottom:
1.25em;padding:
1.25em;background:#f8f8f7;border-radius:
4px}
179 #content #toc
>:first-child{margin-top:
0}
180 #content #toc
>:last-child{margin-bottom:
0}
181 #footer{max-width:none;background:rgba(
0,
0,
0,
.8);padding:
1.25em}
182 #footer-text{color:hsla(
0,
0%,
100%,
.8);line-height:
1.44}
183 #content{margin-bottom:
.625em}
184 .sect1{padding-bottom:
.625em}
185 @media screen and (min-width:
768px){#content{margin-bottom:
1.25em}
186 .sect1{padding-bottom:
1.25em}}
187 .sect1:last-child{padding-bottom:
0}
188 .sect1+.sect1{border-top:
1px solid #e7e7e9}
189 #content h1
>a.anchor,h2
>a.anchor,h3
>a.anchor,#toctitle
>a.anchor,.sidebarblock
>.content
>.title
>a.anchor,h4
>a.anchor,h5
>a.anchor,h6
>a.anchor{position:absolute;z-index:
1001;width:
1.5ex;margin-left:-
1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:
400}
190 #content h1
>a.anchor::before,h2
>a.anchor::before,h3
>a.anchor::before,#toctitle
>a.anchor::before,.sidebarblock
>.content
>.title
>a.anchor::before,h4
>a.anchor::before,h5
>a.anchor::before,h6
>a.anchor::before{content:
"\00A7";font-size:
.85em;display:block;padding-top:
.1em}
191 #content h1:hover
>a.anchor,#content h1
>a.anchor:hover,h2:hover
>a.anchor,h2
>a.anchor:hover,h3:hover
>a.anchor,#toctitle:hover
>a.anchor,.sidebarblock
>.content
>.title:hover
>a.anchor,h3
>a.anchor:hover,#toctitle
>a.anchor:hover,.sidebarblock
>.content
>.title
>a.anchor:hover,h4:hover
>a.anchor,h4
>a.anchor:hover,h5:hover
>a.anchor,h5
>a.anchor:hover,h6:hover
>a.anchor,h6
>a.anchor:hover{visibility:visible}
192 #content h1
>a.link,h2
>a.link,h3
>a.link,#toctitle
>a.link,.sidebarblock
>.content
>.title
>a.link,h4
>a.link,h5
>a.link,h6
>a.link{color:#ba3925;text-decoration:none}
193 #content h1
>a.link:hover,h2
>a.link:hover,h3
>a.link:hover,#toctitle
>a.link:hover,.sidebarblock
>.content
>.title
>a.link:hover,h4
>a.link:hover,h5
>a.link:hover,h6
>a.link:hover{color:#a53221}
194 details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:
1.25em}
195 details{margin-left:
1.25rem}
196 details
>summary{cursor:pointer;display:block;position:relative;line-height:
1.6;margin-bottom:
.625rem;outline:none;-webkit-tap-highlight-color:transparent}
197 details
>summary::-webkit-details-marker{display:none}
198 details
>summary::before{content:
"";border:solid transparent;border-left:solid;border-width:
.3em
0 .3em
.5em;position:absolute;top:
.5em;left:-
1.25rem;transform:translateX(
15%)}
199 details[open]
>summary::before{border:solid transparent;border-top:solid;border-width:
.5em
.3em
0;transform:translateY(
15%)}
200 details
>summary::after{content:
"";width:
1.25rem;height:
1em;position:absolute;top:
.3em;left:-
1.25rem}
201 .admonitionblock td.content
>.title,.audioblock
>.title,.exampleblock
>.title,.imageblock
>.title,.listingblock
>.title,.literalblock
>.title,.stemblock
>.title,.openblock
>.title,.paragraph
>.title,.quoteblock
>.title,table.tableblock
>.title,.verseblock
>.title,.videoblock
>.title,.dlist
>.title,.olist
>.title,.ulist
>.title,.qlist
>.title,.hdlist
>.title{text-rendering:optimizeLegibility;text-align:left;font-family:
"Noto Serif",
"DejaVu Serif",serif;font-size:
1rem;font-style:italic}
202 table.tableblock.fit-content
>caption.title{white-space:nowrap;width:
0}
203 .paragraph.lead
>p,#preamble
>.sectionbody
>[class=paragraph]:first-of-type p{font-size:
1.21875em;line-height:
1.6;color:rgba(
0,
0,
0,
.85)}
204 .admonitionblock
>table{border-collapse:separate;border:
0;background:none;width:
100%}
205 .admonitionblock
>table td.icon{text-align:center;width:
80px}
206 .admonitionblock
>table td.icon img{max-width:none}
207 .admonitionblock
>table td.icon .title{font-weight:bold;font-family:
"Open Sans",
"DejaVu Sans",sans-serif;text-transform:uppercase}
208 .admonitionblock
>table td.content{padding-left:
1.125em;padding-right:
1.25em;border-left:
1px solid #dddddf;color:rgba(
0,
0,
0,
.6);word-wrap:anywhere}
209 .admonitionblock
>table td.content
>:last-child
>:last-child{margin-bottom:
0}
210 .exampleblock
>.content{border:
1px solid #e6e6e6;margin-bottom:
1.25em;padding:
1.25em;background:#fff;border-radius:
4px}
211 .sidebarblock{border:
1px solid #dbdbd6;margin-bottom:
1.25em;padding:
1.25em;background:#f3f3f2;border-radius:
4px}
212 .sidebarblock
>.content
>.title{color:#
7a2518;margin-top:
0;text-align:center}
213 .exampleblock
>.content
>:first-child,.sidebarblock
>.content
>:first-child{margin-top:
0}
214 .exampleblock
>.content
>:last-child,.exampleblock
>.content
>:last-child
>:last-child,.exampleblock
>.content .olist
>ol
>li:last-child
>:last-child,.exampleblock
>.content .ulist
>ul
>li:last-child
>:last-child,.exampleblock
>.content .qlist
>ol
>li:last-child
>:last-child,.sidebarblock
>.content
>:last-child,.sidebarblock
>.content
>:last-child
>:last-child,.sidebarblock
>.content .olist
>ol
>li:last-child
>:last-child,.sidebarblock
>.content .ulist
>ul
>li:last-child
>:last-child,.sidebarblock
>.content .qlist
>ol
>li:last-child
>:last-child{margin-bottom:
0}
215 .literalblock pre,.listingblock
>.content
>pre{border-radius:
4px;overflow-x:auto;padding:
1em;font-size:
.8125em}
216 @media screen and (min-width:
768px){.literalblock pre,.listingblock
>.content
>pre{font-size:
.90625em}}
217 @media screen and (min-width:
1280px){.literalblock pre,.listingblock
>.content
>pre{font-size:
1em}}
218 .literalblock pre,.listingblock
>.content
>pre:not(.highlight),.listingblock
>.content
>pre[class=highlight],.listingblock
>.content
>pre[class^=
"highlight "]{background:#f7f7f8}
219 .literalblock.output pre{color:#f7f7f8;background:rgba(
0,
0,
0,
.9)}
220 .listingblock
>.content{position:relative}
221 .listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:
.75em;top:
.425rem;right:
.5rem;line-height:
1;text-transform:uppercase;color:inherit;opacity:
.5}
222 .listingblock:hover code[data-lang]::before{display:block}
223 .listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:
.5em;color:inherit;opacity:
.5}
224 .listingblock.terminal pre .command:not([data-prompt])::before{content:
"$"}
225 .listingblock pre.highlightjs{padding:
0}
226 .listingblock pre.highlightjs
>code{padding:
1em;border-radius:
4px}
227 .listingblock pre.prettyprint{border-width:
0}
228 .prettyprint{background:#f7f7f8}
229 pre.prettyprint .linenums{line-height:
1.45;margin-left:
2em}
230 pre.prettyprint li{background:none;list-style-type:inherit;padding-left:
0}
231 pre.prettyprint li code[data-lang]::before{opacity:
1}
232 pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none}
233 table.linenotable{border-collapse:separate;border:
0;margin-bottom:
0;background:none}
234 table.linenotable td[class]{color:inherit;vertical-align:top;padding:
0;line-height:inherit;white-space:normal}
235 table.linenotable td.code{padding-left:
.75em}
236 table.linenotable td.linenos,pre.pygments .linenos{border-right:
1px solid;opacity:
.35;padding-right:
.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
237 pre.pygments span.linenos{display:inline-block;margin-right:
.75em}
238 .quoteblock{margin:
0 1em
1.25em
1.5em;display:table}
239 .quoteblock:not(.excerpt)
>.title{margin-left:-
1.5em;margin-bottom:
.75em}
240 .quoteblock blockquote,.quoteblock p{color:rgba(
0,
0,
0,
.85);font-size:
1.15rem;line-height:
1.75;word-spacing:
.1em;letter-spacing:
0;font-style:italic;text-align:justify}
241 .quoteblock blockquote{margin:
0;padding:
0;border:
0}
242 .quoteblock blockquote::before{content:
"\201c";float:left;font-size:
2.75em;font-weight:bold;line-height:
.6em;margin-left:-
.6em;color:#
7a2518;text-shadow:
0 1px
2px rgba(
0,
0,
0,
.1)}
243 .quoteblock blockquote
>.paragraph:last-child p{margin-bottom:
0}
244 .quoteblock .attribution{margin-top:
.75em;margin-right:
.5ex;text-align:right}
245 .verseblock{margin:
0 1em
1.25em}
246 .verseblock pre{font-family:
"Open Sans",
"DejaVu Sans",sans-serif;font-size:
1.15rem;color:rgba(
0,
0,
0,
.85);font-weight:
300;text-rendering:optimizeLegibility}
247 .verseblock pre strong{font-weight:
400}
248 .verseblock .attribution{margin-top:
1.25rem;margin-left:
.5ex}
249 .quoteblock .attribution,.verseblock .attribution{font-size:
.9375em;line-height:
1.45;font-style:italic}
250 .quoteblock .attribution br,.verseblock .attribution br{display:none}
251 .quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-
.025em;color:rgba(
0,
0,
0,
.6)}
252 .quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}
253 .quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:
1.6;word-spacing:
0}
254 .quoteblock.abstract{margin:
0 1em
1.25em;display:block}
255 .quoteblock.abstract
>.title{margin:
0 0 .375em;font-size:
1.15em;text-align:center}
256 .quoteblock.excerpt
>blockquote,.quoteblock .quoteblock{padding:
0 0 .25em
1em;border-left:
.25em solid #dddddf}
257 .quoteblock.excerpt,.quoteblock .quoteblock{margin-left:
0}
258 .quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:
1.0625rem}
259 .quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;font-size:
.85rem;text-align:left;margin-right:
0}
260 p.tableblock:last-child{margin-bottom:
0}
261 td.tableblock
>.content{margin-bottom:
1.25em;word-wrap:anywhere}
262 td.tableblock
>.content
>:last-child{margin-bottom:-
1.25em}
263 table.tableblock,th.tableblock,td.tableblock{border:
0 solid #dedede}
264 table.grid-all
>*
>tr
>*{border-width:
1px}
265 table.grid-cols
>*
>tr
>*{border-width:
0 1px}
266 table.grid-rows
>*
>tr
>*{border-width:
1px
0}
267 table.frame-all{border-width:
1px}
268 table.frame-ends{border-width:
1px
0}
269 table.frame-sides{border-width:
0 1px}
270 table.frame-none
>colgroup+*
>:first-child
>*,table.frame-sides
>colgroup+*
>:first-child
>*{border-top-width:
0}
271 table.frame-none
>:last-child
>:last-child
>*,table.frame-sides
>:last-child
>:last-child
>*{border-bottom-width:
0}
272 table.frame-none
>*
>tr
>:first-child,table.frame-ends
>*
>tr
>:first-child{border-left-width:
0}
273 table.frame-none
>*
>tr
>:last-child,table.frame-ends
>*
>tr
>:last-child{border-right-width:
0}
274 table.stripes-all
>*
>tr,table.stripes-odd
>*
>tr:nth-of-type(odd),table.stripes-even
>*
>tr:nth-of-type(even),table.stripes-hover
>*
>tr:hover{background:#f8f8f7}
275 th.halign-left,td.halign-left{text-align:left}
276 th.halign-right,td.halign-right{text-align:right}
277 th.halign-center,td.halign-center{text-align:center}
278 th.valign-top,td.valign-top{vertical-align:top}
279 th.valign-bottom,td.valign-bottom{vertical-align:bottom}
280 th.valign-middle,td.valign-middle{vertical-align:middle}
281 table thead th,table tfoot th{font-weight:bold}
282 tbody tr th{background:#f7f8f7}
283 tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(
0,
0,
0,
.8);font-weight:bold}
284 p.tableblock
>code:only-child{background:none;padding:
0}
285 p.tableblock{font-size:
1em}
286 ol{margin-left:
1.75em}
287 ul li ol{margin-left:
1.5em}
288 dl dd{margin-left:
1.125em}
289 dl dd:last-child,dl dd:last-child
>:last-child{margin-bottom:
0}
290 li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:
.625em}
291 ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
292 ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:
.625em}
293 ul.unstyled,ol.unstyled{margin-left:
0}
294 li
>p:empty:only-child::before{content:
"";display:inline-block}
295 ul.checklist
>li
>p:first-child{margin-left:-
1em}
296 ul.checklist
>li
>p:first-child
>.fa-square-o:first-child,ul.checklist
>li
>p:first-child
>.fa-check-square-o:first-child{width:
1.25em;font-size:
.8em;position:relative;bottom:
.125em}
297 ul.checklist
>li
>p:first-child
>input[type=checkbox]:first-child{margin-right:
.25em}
298 ul.inline{display:flex;flex-flow:row wrap;list-style:none;margin:
0 0 .625em -
1.25em}
299 ul.inline
>li{margin-left:
1.25em}
300 .unstyled dl dt{font-weight:
400;font-style:normal}
301 ol.arabic{list-style-type:decimal}
302 ol.decimal{list-style-type:decimal-leading-zero}
303 ol.loweralpha{list-style-type:lower-alpha}
304 ol.upperalpha{list-style-type:upper-alpha}
305 ol.lowerroman{list-style-type:lower-roman}
306 ol.upperroman{list-style-type:upper-roman}
307 ol.lowergreek{list-style-type:lower-greek}
308 .hdlist
>table,.colist
>table{border:
0;background:none}
309 .hdlist
>table
>tbody
>tr,.colist
>table
>tbody
>tr{background:none}
310 td.hdlist1,td.hdlist2{vertical-align:top;padding:
0 .625em}
311 td.hdlist1{font-weight:bold;padding-bottom:
1.25em}
312 td.hdlist2{word-wrap:anywhere}
313 .literalblock+.colist,.listingblock+.colist{margin-top:-
.5em}
314 .colist td:not([class]):first-child{padding:
.4em
.75em
0;line-height:
1;vertical-align:top}
315 .colist td:not([class]):first-child img{max-width:none}
316 .colist td:not([class]):last-child{padding:
.25em
0}
317 .thumb,.th{line-height:
0;display:inline-block;border:
4px solid #fff;box-shadow:
0 0 0 1px #ddd}
318 .imageblock.left{margin:
.25em
.625em
1.25em
0}
319 .imageblock.right{margin:
.25em
0 1.25em
.625em}
320 .imageblock
>.title{margin-bottom:
0}
321 .imageblock.thumb,.imageblock.th{border-width:
6px}
322 .imageblock.thumb
>.title,.imageblock.th
>.title{padding:
0 .125em}
323 .image.left,.image.right{margin-top:
.25em;margin-bottom:
.25em;display:inline-block;line-height:
0}
324 .image.left{margin-right:
.625em}
325 .image.right{margin-left:
.625em}
326 a.image{text-decoration:none;display:inline-block}
327 a.image object{pointer-events:none}
328 sup.footnote,sup.footnoteref{font-size:
.875em;position:static;vertical-align:super}
329 sup.footnote a,sup.footnoteref a{text-decoration:none}
330 sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
331 #footnotes{padding-top:
.75em;padding-bottom:
.75em;margin-bottom:
.625em}
332 #footnotes hr{width:
20%;min-width:
6.25em;margin:-
.25em
0 .75em;border-width:
1px
0 0}
333 #footnotes .footnote{padding:
0 .375em
0 .225em;line-height:
1.3334;font-size:
.875em;margin-left:
1.2em;margin-bottom:
.2em}
334 #footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-
1.05em}
335 #footnotes .footnote:last-of-type{margin-bottom:
0}
336 #content #footnotes{margin-top:-
.625em;margin-bottom:
0;padding:
.75em
0}
337 div.unbreakable{page-break-inside:avoid}
338 .big{font-size:larger}
339 .small{font-size:smaller}
340 .underline{text-decoration:underline}
341 .overline{text-decoration:overline}
342 .line-through{text-decoration:line-through}
344 .aqua-background{background:#
00fafa}
346 .black-background{background:#
000}
348 .blue-background{background:#
0000fa}
349 .fuchsia{color:#bf00bf}
350 .fuchsia-background{background:#fa00fa}
352 .gray-background{background:#
7d7d7d}
353 .green{color:#
006000}
354 .green-background{background:#
007d00}
356 .lime-background{background:#
00fa00}
357 .maroon{color:#
600000}
358 .maroon-background{background:#
7d0000}
360 .navy-background{background:#
00007d}
361 .olive{color:#
606000}
362 .olive-background{background:#
7d7d00}
363 .purple{color:#
600060}
364 .purple-background{background:#
7d007d}
366 .red-background{background:#fa0000}
367 .silver{color:#
909090}
368 .silver-background{background:#bcbcbc}
370 .teal-background{background:#
007d7d}
371 .white{color:#bfbfbf}
372 .white-background{background:#fafafa}
373 .yellow{color:#bfbf00}
374 .yellow-background{background:#fafa00}
375 span.icon
>.fa{cursor:default}
376 a span.icon
>.fa{cursor:inherit}
377 .admonitionblock td.icon [class^=
"fa icon-"]{font-size:
2.5em;text-shadow:
1px
1px
2px rgba(
0,
0,
0,
.5);cursor:default}
378 .admonitionblock td.icon .icon-note::before{content:
"\f05a";color:#
19407c}
379 .admonitionblock td.icon .icon-tip::before{content:
"\f0eb";text-shadow:
1px
1px
2px rgba(
155,
155,
0,
.8);color:#
111}
380 .admonitionblock td.icon .icon-warning::before{content:
"\f071";color:#bf6900}
381 .admonitionblock td.icon .icon-caution::before{content:
"\f06d";color:#bf3400}
382 .admonitionblock td.icon .icon-important::before{content:
"\f06a";color:#bf0000}
383 .conum[data-value]{display:inline-block;color:#fff!important;background:rgba(
0,
0,
0,
.8);border-radius:
50%;text-align:center;font-size:
.75em;width:
1.67em;height:
1.67em;line-height:
1.67em;font-family:
"Open Sans",
"DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
384 .conum[data-value] *{color:#fff!important}
385 .conum[data-value]+b{display:none}
386 .conum[data-value]::after{content:attr(data-value)}
387 pre .conum[data-value]{position:relative;top:-
.125em}
388 b.conum *{color:inherit!important}
389 .conum:not([data-value]):empty{display:none}
390 dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
391 h1,h2,p,td.content,span.alt,summary{letter-spacing:-
.01em}
392 p strong,td.content strong,div.footnote strong{letter-spacing:-
.005em}
393 p,blockquote,dt,td.content,td.hdlist1,span.alt,summary{font-size:
1.0625rem}
394 p{margin-bottom:
1.25rem}
395 .sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:
1em}
396 .exampleblock
>.content{background:#fffef7;border-color:#e0e0dc;box-shadow:
0 1px
4px #e0e0dc}
397 .print-only{display:none!important}
398 @page{margin:
1.25cm
.75cm}
399 @media print{*{box-shadow:none!important;text-shadow:none!important}
401 a{color:inherit!important;text-decoration:underline!important}
402 a.bare,a[href^=
"#"],a[href^=
"mailto:"]{text-decoration:none!important}
403 a[href^=
"http:"]:not(.bare)::after,a[href^=
"https:"]:not(.bare)::after{content:
"(" attr(href)
")";display:inline-block;font-size:
.875em;padding-left:
.25em}
404 abbr[title]{border-bottom:
1px dotted}
405 abbr[title]::after{content:
" (" attr(title)
")"}
406 pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
407 thead{display:table-header-group}
409 p,blockquote,dt,td.content{font-size:
1em;orphans:
3;widows:
3}
410 h2,h3,#toctitle,.sidebarblock
>.content
>.title{page-break-after:avoid}
411 #header,#content,#footnotes,#footer{max-width:none}
412 #toc,.sidebarblock,.exampleblock
>.content{background:none!important}
413 #toc{border-bottom:
1px solid #dddddf!important;padding-bottom:
0!important}
414 body.book #header{text-align:center}
415 body.book #header
>h1:first-child{border:
0!important;margin:
2.5em
0 1em}
416 body.book #header .details{border:
0!important;display:block;padding:
0!important}
417 body.book #header .details span:first-child{margin-left:
0!important}
418 body.book #header .details br{display:block}
419 body.book #header .details br+span::before{content:none!important}
420 body.book #toc{border:
0!important;text-align:left!important;padding:
0!important;margin:
0!important}
421 body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1
>h2{page-break-before:always}
422 .listingblock code[data-lang]::before{display:block}
423 #footer{padding:
0 .9375em}
424 .hide-on-print{display:none!important}
425 .print-only{display:block!important}
426 .hide-for-print{display:none!important}
427 .show-for-print{display:inherit!important}}
428 @media amzn-kf8,print{#header
>h1:first-child{margin-top:
1.25rem}
429 .sect1{padding:
0!important}
430 .sect1+.sect1{border:
0}
431 #footer{background:none}
432 #footer-text{color:rgba(
0,
0,
0,
.6);font-size:
.9em}}
433 @media amzn-kf8{#header,#content,#footnotes,#footer{padding:
0}}
441 <body class=
"article">
443 <h1>How to recover an object from scratch
</h1>
447 <div class=
"sectionbody">
448 <div class=
"paragraph">
449 <p>I was recently presented with a repository with a corrupted packfile,
450 and was asked if the data was recoverable. This post-mortem describes
451 the steps I took to investigate and fix the problem. I thought others
452 might find the process interesting, and it might help somebody in the
455 <div class=
"sidebarblock">
456 <div class=
"content">
457 <div class=
"paragraph">
458 <p>Note: In this case, no good copy of the repository was available. For
459 the much easier case where you can get the corrupted object from
460 elsewhere, see
<a href=
"recover-corrupted-blob-object.html">this howto
</a>.
</p>
464 <div class=
"paragraph">
465 <p>I started with an fsck, which found a problem with exactly one object
466 (I
’ve used $pack and $obj below to keep the output readable, and also
467 because I
’ll refer to them later):
</p>
469 <div class=
"listingblock">
470 <div class=
"content">
472 error: $pack SHA1 checksum mismatch
473 error: index CRC mismatch for object $obj from $pack at offset
51653873
474 error: inflate: data stream error (incorrect data check)
475 error: cannot unpack $obj from $pack at offset
51653873</pre>
478 <div class=
"paragraph">
479 <p>The pack checksum failing means a byte is munged somewhere, and it is
480 presumably in the object mentioned (since both the index checksum and
481 zlib were failing).
</p>
483 <div class=
"paragraph">
484 <p>Reading the zlib source code, I found that
"incorrect data check" means
485 that the adler-
32 checksum at the end of the zlib data did not match the
486 inflated data. So stepping the data through zlib would not help, as it
487 did not fail until the very end, when we realize the CRC does not match.
488 The problematic bytes could be anywhere in the object data.
</p>
490 <div class=
"paragraph">
491 <p>The first thing I did was pull the broken data out of the packfile. I
492 needed to know how big the object was, which I found out with:
</p>
494 <div class=
"listingblock">
495 <div class=
"content">
496 <pre> $ git show-index
<$idx | cut -d' ' -f1 | sort -n | grep -A1
51653873
501 <div class=
"paragraph">
502 <p>Show-index gives us the list of objects and their offsets. We throw away
503 everything but the offsets, and then sort them so that our interesting
504 offset (which we got from the fsck output above) is followed immediately
505 by the offset of the next object. Now we know that the object data is
506 10863 bytes long, and we can grab it with:
</p>
508 <div class=
"listingblock">
509 <div class=
"content">
510 <pre> dd if=$pack of=object bs=
1 skip=
51653873 count=
10863</pre>
513 <div class=
"paragraph">
514 <p>I inspected a hexdump of the data, looking for any obvious bogosity
515 (e.g., a
4K run of zeroes would be a good sign of filesystem
516 corruption). But everything looked pretty reasonable.
</p>
518 <div class=
"paragraph">
519 <p>Note that the
"object" file isn
’t fit for feeding straight to zlib; it
520 has the git packed object header, which is variable-length. We want to
521 strip that off so we can start playing with the zlib data directly. You
522 can either work your way through it manually (the format is described in
523 <a href=
"../gitformat-pack.html">gitformat-pack(
5)
</a>),
524 or you can walk through it in a debugger. I did the latter, creating a
527 <div class=
"listingblock">
528 <div class=
"content">
529 <pre> # pack magic and version
530 printf 'PACK\
0\
0\
0\
2'
>tmp.pack
531 # pack has one object
532 printf '\
0\
0\
0\
1'
>>tmp.pack
533 # now add our object data
534 cat object
>>tmp.pack
535 # and then append the pack trailer
536 /path/to/git.git/t/helper/test-tool sha1 -b
<tmp.pack
>trailer
537 cat trailer
>>tmp.pack
</pre>
540 <div class=
"paragraph">
541 <p>and then running
"git index-pack tmp.pack" in the debugger (stop at
542 unpack_raw_entry). Doing this, I found that there were
3 bytes of header
543 (and the header itself had a sane type and size). So I stripped those
546 <div class=
"listingblock">
547 <div class=
"content">
548 <pre> dd if=object of=zlib bs=
1 skip=
3</pre>
551 <div class=
"paragraph">
552 <p>I ran the result through zlib
’s inflate using a custom C program. And
553 while it did report the error, I did get the right number of output
554 bytes (i.e., it matched git
’s size header that we decoded above). But
555 feeding the result back to
"git hash-object" didn
’t produce the same
556 sha1. So there were some wrong bytes, but I didn
’t know which. The file
557 happened to be C source code, so I hoped I could notice something
558 obviously wrong with it, but I didn
’t. I even got it to compile!
</p>
560 <div class=
"paragraph">
561 <p>I also tried comparing it to other versions of the same path in the
562 repository, hoping that there would be some part of the diff that didn
’t
563 make sense. Unfortunately, this happened to be the only revision of this
564 particular file in the repository, so I had nothing to compare against.
</p>
566 <div class=
"paragraph">
567 <p>So I took a different approach. Working under the guess that the
568 corruption was limited to a single byte, I wrote a program to munge each
569 byte individually, and try inflating the result. Since the object was
570 only
10K compressed, that worked out to about
2.5M attempts, which took
573 <div class=
"paragraph">
574 <p>The program I used is here:
</p>
576 <div class=
"listingblock">
577 <div class=
"content">
578 <pre>#include
<stdio.h
>
579 #include
<unistd.h
>
580 #include
<string.h
>
581 #include
<signal.h
>
582 #include
<zlib.h
>
584 static int try_zlib(unsigned char *buf, int len)
586 /* make this absurdly large so we don't have to loop */
587 static unsigned char out[
1024*
1024];
591 memset(
&z,
0, sizeof(z));
597 z.avail_out = sizeof(out);
599 ret = inflate(
&z,
0);
605 static int counter =
0;
606 static void progress(int sig)
608 fprintf(stderr,
"\r%d", counter);
614 /* oversized so we can read the whole buffer in */
615 unsigned char buf[
1024*
1024];
619 signal(SIGALRM, progress);
622 len = read(
0, buf, sizeof(buf));
623 for (i =
0; i
< len; i++) {
624 unsigned char c = buf[i];
625 for (j =
0; j
<=
0xff; j++) {
629 if (try_zlib(buf, len))
630 printf(
"i=%d, j=%x\n", i, j);
636 fprintf(stderr,
"\n");
641 <div class=
"paragraph">
642 <p>I compiled and ran with:
</p>
644 <div class=
"listingblock">
645 <div class=
"content">
646 <pre> gcc -Wall -Werror -O3 munge.c -o munge -lz
647 ./munge
<zlib
</pre>
650 <div class=
"paragraph">
651 <p>There were a few false positives early on (if you write
"no data" in the
652 zlib header, zlib thinks it
’s just fine :) ). But I got a hit about
655 <div class=
"listingblock">
656 <div class=
"content">
657 <pre> i=
5642, j=c7
</pre>
660 <div class=
"paragraph">
661 <p>I let it run to completion, and got a few more hits at the end (where it
662 was munging the CRC to match our broken data). So there was a good
663 chance this middle hit was the source of the problem.
</p>
665 <div class=
"paragraph">
666 <p>I confirmed by tweaking the byte in a hex editor, zlib inflating the
667 result (no errors!), and then piping the output into
"git hash-object",
668 which reported the sha1 of the broken object. Success!
</p>
670 <div class=
"paragraph">
671 <p>I fixed the packfile itself with:
</p>
673 <div class=
"listingblock">
674 <div class=
"content">
676 printf '\xc7' | dd of=$pack bs=
1 seek=
51659518 conv=notrunc
680 <div class=
"paragraph">
681 <p>The \xc7 comes from the replacement byte our
"munge" program found.
682 The offset
51659518 is derived by taking the original object offset
683 (
51653873), adding the replacement offset found by
"munge" (
5642), and
684 then adding back in the
3 bytes of git header we stripped.
</p>
686 <div class=
"paragraph">
687 <p>After that,
"git fsck" ran clean.
</p>
689 <div class=
"paragraph">
690 <p>As for the corruption itself, I was lucky that it was indeed a single
691 byte. In fact, it turned out to be a single bit. The byte
0xc7 was
692 corrupted to
0xc5. So presumably it was caused by faulty hardware, or a
695 <div class=
"paragraph">
696 <p>And the aborted attempt to look at the inflated output to see what was
697 wrong? I could have looked forever and never found it. Here
’s the diff
698 between what the corrupted data inflates to, versus the real data:
</p>
700 <div class=
"listingblock">
701 <div class=
"content">
702 <pre> - cp = strtok (arg,
"+");
703 + cp = strtok (arg,
".");
</pre>
706 <div class=
"paragraph">
707 <p>It tweaked one byte and still ended up as valid, readable C that just
708 happened to do something totally different! One takeaway is that on a
709 less unlucky day, looking at the zlib output might have actually been
710 helpful, as most random changes would actually break the C code.
</p>
712 <div class=
"paragraph">
713 <p>But more importantly, git
’s hashing and checksumming noticed a problem
714 that easily could have gone undetected in another system. The result
715 still compiled, but would have caused an interesting bug (that would
716 have been blamed on some random commit).
</p>
721 <h2 id=
"_the_adventure_continues">The adventure continues
…​</h2>
722 <div class=
"sectionbody">
723 <div class=
"paragraph">
724 <p>I ended up doing this again! Same entity, new hardware. The assumption
725 at this point is that the old disk corrupted the packfile, and then the
726 corruption was migrated to the new hardware (because it was done by
727 rsync or similar, and no fsck was done at the time of migration).
</p>
729 <div class=
"paragraph">
730 <p>This time, the affected blob was over
20 megabytes, which was far too
731 large to do a brute-force on. I followed the instructions above to
732 create the
<code>zlib
</code> file. I then used the
<code>inflate
</code> program below to pull
733 the corrupted data from that. Examining that output gave me a hint about
734 where in the file the corruption was. But now I was working with the
735 file itself, not the zlib contents. So knowing the sha1 of the object
736 and the approximate area of the corruption, I used the
<code>sha1-munge
</code>
737 program below to brute-force the correct byte.
</p>
739 <div class=
"paragraph">
740 <p>Here
’s the inflate program (it
’s essentially
<code>gunzip
</code> but without the
741 .
<code>gz
</code> header processing):
</p>
743 <div class=
"listingblock">
744 <div class=
"content">
745 <pre>#include
<stdio.h
>
746 #include
<string.h
>
747 #include
<zlib.h
>
748 #include
<stdlib.h
>
750 int main(int argc, char **argv)
753 * oversized so we can read the whole buffer in;
754 * this could actually be switched to streaming
755 * to avoid any memory limitations
757 static unsigned char buf[
25 *
1024 *
1024];
758 static unsigned char out[
25 *
1024 *
1024];
763 len = read(
0, buf, sizeof(buf));
764 memset(
&z,
0, sizeof(z));
770 z.avail_out = sizeof(out);
772 ret = inflate(
&z,
0);
773 if (ret != Z_OK
&& ret != Z_STREAM_END)
774 fprintf(stderr,
"initial inflate failed (%d)\n", ret);
776 fprintf(stderr,
"outputting %lu bytes", z.total_out);
777 fwrite(out,
1, z.total_out, stdout);
782 <div class=
"paragraph">
783 <p>And here is the
<code>sha1-munge
</code> program:
</p>
785 <div class=
"listingblock">
786 <div class=
"content">
787 <pre>#include
<stdio.h
>
788 #include
<unistd.h
>
789 #include
<string.h
>
790 #include
<signal.h
>
791 #include
<openssl/sha.h
>
792 #include
<stdlib.h
>
795 static int counter =
0;
796 static void progress(int sig)
798 fprintf(stderr,
"\r%d", counter);
802 static const signed char hexval_table[
256] = {
803 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /*
00-
07 */
804 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /*
08-
0f */
805 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /*
10-
17 */
806 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /*
18-
1f */
807 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /*
20-
27 */
808 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /*
28-
2f */
809 0,
1,
2,
3,
4,
5,
6,
7, /*
30-
37 */
810 8,
9, -
1, -
1, -
1, -
1, -
1, -
1, /*
38-
3f */
811 -
1,
10,
11,
12,
13,
14,
15, -
1, /*
40-
47 */
812 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /*
48-
4f */
813 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /*
50-
57 */
814 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /*
58-
5f */
815 -
1,
10,
11,
12,
13,
14,
15, -
1, /*
60-
67 */
816 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /*
68-
67 */
817 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /*
70-
77 */
818 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /*
78-
7f */
819 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /*
80-
87 */
820 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /*
88-
8f */
821 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /*
90-
97 */
822 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /*
98-
9f */
823 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /* a0-a7 */
824 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /* a8-af */
825 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /* b0-b7 */
826 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /* b8-bf */
827 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /* c0-c7 */
828 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /* c8-cf */
829 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /* d0-d7 */
830 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /* d8-df */
831 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /* e0-e7 */
832 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /* e8-ef */
833 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /* f0-f7 */
834 -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, /* f8-ff */
837 static inline unsigned int hexval(unsigned char c)
839 return hexval_table[c];
842 static int get_sha1_hex(const char *hex, unsigned char *sha1)
845 for (i =
0; i
< 20; i++) {
848 * hex[
1]=='\
0' is caught when val is checked below,
849 * but if hex[
0] is NUL we have to avoid reading
850 * past the end of the string:
854 val = (hexval(hex[
0])
<< 4) | hexval(hex[
1]);
863 int main(int argc, char **argv)
865 /* oversized so we can read the whole buffer in */
866 static unsigned char buf[
25 *
1024 *
1024];
869 unsigned char have[
20], want[
20];
874 if (!argv[
1] || get_sha1_hex(argv[
1], want)) {
875 fprintf(stderr,
"usage: sha1-munge <sha1> [start] <file.in\n");
880 start = atoi(argv[
2]);
884 len = read(
0, buf, sizeof(buf));
885 header_len = sprintf(header,
"blob %d", len) +
1;
886 fprintf(stderr,
"using header: %s\n", header);
889 * We keep a running sha1 so that if you are munging
890 * near the end of the file, we do not have to re-sha1
891 * the unchanged earlier bytes
893 SHA1_Init(
&orig);
894 SHA1_Update(
&orig, header, header_len);
896 SHA1_Update(
&orig, buf, start);
898 signal(SIGALRM, progress);
901 for (i = start; i
< len; i++) {
907 * deletion -- this would not actually work in practice,
908 * I think, because we've already committed to a
909 * particular size in the header. Ditto for addition
910 * below. In those cases, you'd have to do the whole
911 * sha1 from scratch, or possibly keep three running
912 *
"orig" sha1 computations going.
914 memcpy(
&x,
&orig, sizeof(x));
915 SHA1_Update(
&x, buf + i +
1, len - i -
1);
916 SHA1_Final(have,
&x);
917 if (!memcmp(have, want,
20))
918 printf(
"i=%d, deletion\n", i);
922 * replacement -- note that this tries each of the
256
923 * possible bytes. If you suspect a single-bit flip,
924 * it would be much shorter to just try the
8
925 * bit-flipped variants.
928 for (j =
0; j
<=
0xff; j++) {
931 memcpy(
&x,
&orig, sizeof(x));
932 SHA1_Update(
&x, buf + i, len - i);
933 SHA1_Final(have,
&x);
934 if (!memcmp(have, want,
20))
935 printf(
"i=%d, j=%02x\n", i, j);
941 for (j =
0; j
<=
0xff; j++) {
942 unsigned char extra = j;
943 memcpy(
&x,
&orig, sizeof(x));
944 SHA1_Update(
&x,
&extra,
1);
945 SHA1_Update(
&x, buf + i, len - i);
946 SHA1_Final(have,
&x);
947 if (!memcmp(have, want,
20))
948 printf(
"i=%d, addition=%02x", i, j);
952 SHA1_Update(
&orig, buf + i,
1);
957 fprintf(stderr,
"\r%d\n", counter);
966 <div id=
"footer-text">
967 Last updated
2025-
01-
10 09:
40:
20 -
0800