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