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