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