Line data Source code
1 : #include "../../burp.h"
2 : #include "rabin.h"
3 : #include "rconf.h"
4 : #include "win.h"
5 : #include "../../alloc.h"
6 : #include "../blk.h"
7 : #include "../blist.h"
8 : #include "../../sbuf.h"
9 : #include "../../client/protocol2/rabin_read.h"
10 :
11 : static struct blk *blk=NULL;
12 : static char *gcp=NULL;
13 : static char *gbuf=NULL;
14 : static char *gbuf_end=NULL;
15 : static struct rconf rconf;
16 : static struct win *win=NULL; // Rabin sliding window.
17 : static int first=0;
18 :
19 34 : int blks_generate_init(void)
20 : {
21 34 : rconf_init(&rconf);
22 34 : if(!(win=win_alloc(&rconf))
23 34 : || !(gbuf=(char *)malloc_w(rconf.blk_max, __func__)))
24 : return -1;
25 34 : gbuf_end=gbuf;
26 34 : gcp=gbuf;
27 34 : return 0;
28 : }
29 :
30 41 : void blks_generate_free(void)
31 : {
32 41 : free_w(&gbuf);
33 41 : blk_free(&blk);
34 41 : win_free(&win);
35 41 : }
36 :
37 : // This is where the magic happens.
38 : // Return 1 for got a block, 0 for no block got.
39 28 : static int blk_read(void)
40 : {
41 : unsigned char c;
42 :
43 56 : for(; gcp<gbuf_end; gcp++)
44 : {
45 28 : c=(unsigned char)*gcp;
46 :
47 28 : blk->fingerprint = (blk->fingerprint * rconf.prime) + c;
48 56 : win->checksum = (win->checksum * rconf.prime) + c
49 28 : - (win->data[win->pos] * rconf.multiplier);
50 28 : win->data[win->pos] = c;
51 :
52 28 : win->pos++;
53 28 : if(blk->data)
54 19 : blk->data[blk->length] = c;
55 28 : blk->length++;
56 :
57 28 : if(win->pos == rconf.win_size)
58 0 : win->pos=0;
59 28 : if( blk->length >= rconf.blk_min
60 0 : && (blk->length == rconf.blk_max
61 0 : || (
62 : (win->checksum & 1)
63 : && (win->checksum & 2)
64 0 : && !(win->checksum & 4)
65 0 : && (win->checksum % rconf.blk_avg) == rconf.prime))
66 : ) {
67 0 : gcp++;
68 0 : return 1;
69 : }
70 : }
71 : return 0;
72 : }
73 :
74 29 : static void win_reset(void)
75 : {
76 29 : win->checksum=0;
77 29 : win->pos=0;
78 29 : memset(win->data, 0, rconf.win_size);
79 29 : }
80 :
81 19 : static int blk_read_to_list(struct sbuf *sb, struct blist *blist)
82 : {
83 19 : if(!blk_read()) return 0;
84 :
85 0 : win_reset();
86 :
87 : // Got something.
88 0 : if(first)
89 : {
90 0 : sb->protocol2->bstart=blk;
91 0 : first=0;
92 : }
93 0 : if(!sb->protocol2->bsighead)
94 : {
95 0 : sb->protocol2->bsighead=blk;
96 : }
97 0 : blist_add_blk(blist, blk);
98 0 : blk=NULL;
99 : return 1;
100 : }
101 :
102 : // The client uses this.
103 : // Return 0 for OK. 1 for OK, and file ended, -1 for error.
104 39 : int blks_generate(struct sbuf *sb, struct blist *blist, int just_opened)
105 : {
106 : static ssize_t bytes;
107 39 : first=just_opened;
108 :
109 39 : if(!blk && !(blk=blk_alloc_with_data(rconf.blk_max)))
110 : return -1;
111 :
112 39 : if(first)
113 20 : win_reset();
114 :
115 39 : if(gcp<gbuf_end)
116 : {
117 : // Could have got a fill before buf ran out -
118 : // need to resume from the same place in that case.
119 0 : if(blk_read_to_list(sb, blist))
120 : return 0; // Got a block.
121 : // Did not get a block. Carry on and read more.
122 : }
123 39 : while((bytes=rabin_read(sb, gbuf, rconf.blk_max)))
124 : {
125 19 : gcp=gbuf;
126 19 : gbuf_end=gbuf+bytes;
127 19 : sb->protocol2->bytes_read+=bytes;
128 19 : if(blk_read_to_list(sb, blist))
129 : return 0; // Got a block
130 : // Did not get a block. Maybe should try again?
131 : // If there are async timeouts, look at this!
132 : return 0;
133 : }
134 :
135 : // Getting here means there is no more to read from the file.
136 : // Make sure to deal with anything left over.
137 :
138 20 : if(!sb->protocol2->bytes_read)
139 : {
140 : // Empty file, set up an empty block so that the server
141 : // can skip over it.
142 1 : free_w(&blk->data);
143 1 : sb->protocol2->bstart=blk;
144 1 : sb->protocol2->bsighead=blk;
145 1 : blist_add_blk(blist, blk);
146 1 : blk=NULL;
147 : }
148 19 : else if(blk)
149 : {
150 19 : if(blk->length)
151 : {
152 19 : if(first)
153 : {
154 0 : sb->protocol2->bstart=blk;
155 0 : first=0;
156 : }
157 19 : if(!sb->protocol2->bsighead)
158 : {
159 19 : sb->protocol2->bsighead=blk;
160 : }
161 19 : blist_add_blk(blist, blk);
162 : }
163 0 : else blk_free(&blk);
164 19 : blk=NULL;
165 : }
166 20 : if(blist->tail) sb->protocol2->bend=blist->tail;
167 : return 1;
168 : }
169 :
170 9 : int blk_verify_fingerprint(uint64_t fingerprint, char *data, size_t length)
171 : {
172 9 : win_reset();
173 :
174 9 : memcpy(gbuf, data, length);
175 9 : gbuf_end=gbuf+length;
176 9 : gcp=gbuf;
177 9 : blk_free(&blk);
178 9 : if(!blk && !(blk=blk_alloc())) return -1;
179 9 : blk->length=0;
180 9 : blk->fingerprint=0;
181 :
182 : // FIX THIS: blk_read should return 1 when it has a block.
183 : // But, if the block is too small (because the end of the file
184 : // happened), it returns 0, and blks_generate treats it as having found
185 : // a final block.
186 : // So, here the return of blk_read is ignored and we look at the
187 : // position of gcp instead.
188 9 : blk_read();
189 : //printf("%d %d\n", blk->length, length);
190 : //printf("%016"PRIX64" %016"PRIX64" ",
191 : // blk->fingerprint, fingerprint);
192 : //printf("%s\n", blk->fingerprint==fingerprint?"yes":"no");
193 9 : if(gcp==gbuf_end
194 9 : && blk->fingerprint==fingerprint)
195 : return 1;
196 3 : return 0;
197 : }
|