source: box/trunk/test/backupdiff/difftestfiles.cpp @ 2506

Revision 2506, 6.7 KB checked in by martin, 3 years ago (diff)

Fixes for gcc 4.4.

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    createtestfiles.cpp
5//              Purpose: Create the test files for the backupdiff test
6//              Created: 12/1/04
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#include <string.h>
13#include <stdio.h>
14
15#include "FileStream.h"
16#include "PartialReadStream.h"
17#include "Test.h"
18#include "RollingChecksum.h"
19
20#include "MemLeakFindOn.h"
21
22#define ACT_END         0
23#define ACT_COPY        1
24#define ACT_NEW         2
25#define ACT_SKIP        3
26#define ACT_COPYEND     4
27
28typedef struct
29{
30        int action, length, seed;
31} gen_action;
32
33#define INITIAL_FILE_LENGTH (128*1024 + 342)
34
35
36gen_action file1actions[] = {
37        {ACT_COPYEND, 0, 0},
38        {ACT_END, 0, 0} };
39
40gen_action file2actions[] = {
41        {ACT_COPY, 16*1024, 0},
42        // Do blocks on block boundaries, but swapped around a little
43        {ACT_SKIP, 4*1024, 0},
44        {ACT_COPY, 8*1024, 0},
45        {ACT_SKIP, -12*1024, 0},
46        {ACT_COPY, 4*1024, 0},
47        {ACT_SKIP, 8*1024, 0},
48        // Get rest of file with some new data inserted
49        {ACT_COPY, 37*1024 + 12, 0},
50        {ACT_NEW, 23*1024 + 129, 23990},
51        {ACT_COPYEND, 0, 0},
52        {ACT_END, 0, 0} };
53
54gen_action file3actions[] = {
55        {ACT_COPY, 12*1024 + 983, 0},
56        {ACT_SKIP, 37*1024 + 12, 0},
57        {ACT_COPYEND, 0, 0},
58        {ACT_END, 0, 0} };
59
60gen_action file4actions[] = {
61        {ACT_COPY, 20*1024 + 2385, 0},
62        {ACT_NEW, 12, 2334},
63        {ACT_COPY, 16*1024 + 385, 0},
64        {ACT_SKIP, 9*1024 + 42, 0},
65        {ACT_COPYEND, 0, 0},
66        {ACT_END, 0, 0} };
67
68// insert 1 byte a block into the file, between two other blocks
69gen_action file5actions[] = {
70        {ACT_COPY, 4*1024, 0},
71        {ACT_NEW, 1, 2334},
72        {ACT_COPYEND, 0, 0},
73        {ACT_END, 0, 0} };
74
75gen_action file6actions[] = {
76        {ACT_NEW, 6*1024, 12353452},
77        {ACT_COPYEND, 0, 0},
78        {ACT_END, 0, 0} };
79
80// but delete that one byte block, it's annoying
81gen_action file7actions[] = {
82        {ACT_COPY, 10*1024, 0},
83        {ACT_SKIP, 1, 0},
84        {ACT_COPYEND, 0, 0},
85        {ACT_NEW, 7*1024, 1235352},
86        {ACT_END, 0, 0} };
87
88gen_action file8actions[] = {
89        {ACT_NEW, 54*1024 + 9, 125352},
90        {ACT_END, 0, 0} };
91
92gen_action file9actions[] = {
93        {ACT_END, 0, 0} };
94
95gen_action *testfiles[] = {file1actions, file2actions, file3actions, file4actions,
96        file5actions, file6actions, file7actions, file8actions, file9actions, 0};
97
98
99// Nice random data for testing written files
100class R250 {
101public:
102        // Set up internal state table with 32-bit random numbers. 
103        // The bizarre bit-twiddling is because rand() returns 16 bits of which
104        // the bottom bit is always zero!  Hence, I use only some of the bits.
105        // You might want to do something better than this....
106
107        R250(int seed) : posn1(0), posn2(103)
108        {
109                // populate the state and incr tables
110                srand(seed);
111
112                for (int i = 0; i != stateLen; ++i)     {
113                        state[i] = ((rand() >> 2) << 19) ^ ((rand() >> 2) << 11) ^ (rand() >> 2);
114                        incrTable[i] = i == stateLen - 1 ? 0 : i + 1;
115                }
116
117                // stir up the numbers to ensure they're random
118
119                for (int j = 0; j != stateLen * 4; ++j)                 
120                        (void) next();
121        }
122
123        // Returns the next random number.  Xor together two elements separated
124        // by 103 mod 250, replacing the first element with the result.  Then
125        // increment the two indices mod 250.
126        inline int next()
127        {
128                int ret = (state[posn1] ^= state[posn2]);       // xor and replace element
129
130                posn1 = incrTable[posn1];               // increment indices using lookup table
131                posn2 = incrTable[posn2];
132
133                return ret;
134        }
135private:
136        enum { stateLen = 250 };        // length of the state table
137        int state[stateLen];            // holds the random number state
138        int incrTable[stateLen];        // lookup table: maps i to (i+1) % stateLen
139        int posn1, posn2;                       // indices into the state table
140};
141
142void make_random_data(void *buffer, int size, int seed)
143{
144        R250 rand(seed);
145
146        int n = size / sizeof(int);
147        int *b = (int*)buffer;
148        for(int l = 0; l < n; ++l)
149        {
150                b[l] = rand.next();
151        }
152}
153
154void write_test_data(IOStream &rstream, int size, int seed)
155{
156        R250 rand(seed);
157       
158        while(size > 0)
159        {
160                // make a nice buffer of data
161                int buffer[2048/sizeof(int)];
162                for(unsigned int l = 0; l < (sizeof(buffer) / sizeof(int)); ++l)
163                {
164                        buffer[l] = rand.next();
165                }
166               
167                // Write out...
168                unsigned int w = size;
169                if(w > sizeof(buffer)) w = sizeof(buffer);
170                rstream.Write(buffer, w);
171               
172                size -= w;
173        }       
174}
175
176void gen_varient(IOStream &out, char *sourcename, gen_action *pact)
177{
178        // Open source
179        FileStream source(sourcename);
180       
181        while(true)
182        {
183                switch(pact->action)
184                {
185                case ACT_END:
186                        {
187                                // all done
188                                return;
189                        }
190                case ACT_COPY:
191                        {
192                                PartialReadStream copy(source, pact->length);
193                                copy.CopyStreamTo(out);
194                                break;
195                        }
196                case ACT_NEW:
197                        {
198                                write_test_data(out, pact->length, pact->seed);
199                                break;
200                        }
201                case ACT_SKIP:
202                        {
203                                source.Seek(pact->length, IOStream::SeekType_Relative);
204                                break;
205                        }
206                case ACT_COPYEND:
207                        {
208                                source.CopyStreamTo(out);
209                                break;
210                        }
211                }
212       
213                ++pact;
214        }
215}
216
217void create_test_files()
218{
219        // First, the keys for the crypto
220        {
221                FileStream keys("testfiles/backup.keys", O_WRONLY | O_CREAT);
222                write_test_data(keys, 1024, 237);
223        }
224       
225        // Create the initial file -- needs various special properties...
226        // 1) Two blocks much be the different, but have the same weak checksum
227        // 2) A block must exist twice, but at an offset which isn't a multiple of the block size.
228        {
229                FileStream f0("testfiles/f0", O_WRONLY | O_CREAT);
230                // Write first bit.
231                write_test_data(f0, (16*1024), 20012);
232                // Now repeated checksum blocks
233                uint8_t blk[4096];
234                make_random_data(blk, sizeof(blk), 12201);
235                // Three magic numbers which make the checksum work: Use this perl to find them:
236                /*
237                        for($z = 1; $z < 4096; $z++)
238                        {
239                                for($n = 0; $n <= 255; $n++)
240                                {
241                                        for($m = 0; $m <= 255; $m++)
242                                        {
243                                                if($n != $m && (($n*4096 + $m*(4096-$z)) % (64*1024) == ($n*(4096-$z) + $m*4096) % (64*1024)))
244                                                {
245                                                        print "$z: $n $m\n";
246                                                }
247                                        }
248                                }
249                        }
250                */
251                blk[0] = 255;
252                blk[1024] = 191;
253                // Checksum to check
254                RollingChecksum c1(blk, sizeof(blk));
255                // Write
256                f0.Write(blk, sizeof(blk));
257                // Adjust block and write again
258                uint8_t blk2[4096];
259                memcpy(blk2, blk, sizeof(blk2));
260                blk2[1024] = 255;
261                blk2[0] = 191;
262                TEST_THAT(::memcmp(blk2, blk, sizeof(blk)) != 0);
263                RollingChecksum c2(blk2, sizeof(blk2));
264                f0.Write(blk2, sizeof(blk2));
265                // Check checksums
266                TEST_THAT(c1.GetChecksum() == c2.GetChecksum());
267               
268                // Another 4k block
269                write_test_data(f0, (4*1024), 99209);
270                // Offset block
271                make_random_data(blk, 2048, 1234199);
272                f0.Write(blk, 2048);
273                f0.Write(blk, 2048);
274                f0.Write(blk, 2048);
275                make_random_data(blk, 2048, 1343278);
276                f0.Write(blk, 2048);
277       
278                write_test_data(f0, INITIAL_FILE_LENGTH - (16*1024) - ((4*1024)*2) - (4*1024) - (2048*4), 202);
279       
280        }
281       
282        // Then... create the varients
283        for(int l = 0; testfiles[l] != 0; ++l)
284        {
285                char n1[256];
286                char n2[256];
287                sprintf(n1, "testfiles/f%d", l + 1);
288                sprintf(n2, "testfiles/f%d", l);
289
290                FileStream f1(n1, O_WRONLY | O_CREAT);
291                gen_varient(f1, n2, testfiles[l]);
292        }
293}
294
295
Note: See TracBrowser for help on using the repository browser.