1
2# simple file seek
3[cases.test_seek_read]
4defines = [
5    {COUNT=132, SKIP=4},
6    {COUNT=132, SKIP=128},
7    {COUNT=200, SKIP=10},
8    {COUNT=200, SKIP=100},
9    {COUNT=4,   SKIP=1},
10    {COUNT=4,   SKIP=2},
11]
12code = '''
13    lfs_t lfs;
14    lfs_format(&lfs, cfg) => 0;
15    lfs_mount(&lfs, cfg) => 0;
16    lfs_file_t file;
17    lfs_file_open(&lfs, &file, "kitty",
18            LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
19    size_t size = strlen("kittycatcat");
20    uint8_t buffer[1024];
21    memcpy(buffer, "kittycatcat", size);
22    for (int j = 0; j < COUNT; j++) {
23        lfs_file_write(&lfs, &file, buffer, size);
24    }
25    lfs_file_close(&lfs, &file) => 0;
26    lfs_unmount(&lfs) => 0;
27
28    lfs_mount(&lfs, cfg) => 0;
29    lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY) => 0;
30
31    lfs_soff_t pos = -1;
32    size = strlen("kittycatcat");
33    for (int i = 0; i < SKIP; i++) {
34        lfs_file_read(&lfs, &file, buffer, size) => size;
35        memcmp(buffer, "kittycatcat", size) => 0;
36        pos = lfs_file_tell(&lfs, &file);
37    }
38    assert(pos >= 0);
39
40    lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos;
41    lfs_file_read(&lfs, &file, buffer, size) => size;
42    memcmp(buffer, "kittycatcat", size) => 0;
43
44    lfs_file_rewind(&lfs, &file) => 0;
45    lfs_file_read(&lfs, &file, buffer, size) => size;
46    memcmp(buffer, "kittycatcat", size) => 0;
47
48    lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size;
49    lfs_file_read(&lfs, &file, buffer, size) => size;
50    memcmp(buffer, "kittycatcat", size) => 0;
51
52    lfs_file_seek(&lfs, &file, size, LFS_SEEK_CUR) => 3*size;
53    lfs_file_read(&lfs, &file, buffer, size) => size;
54    memcmp(buffer, "kittycatcat", size) => 0;
55
56    lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos;
57    lfs_file_read(&lfs, &file, buffer, size) => size;
58    memcmp(buffer, "kittycatcat", size) => 0;
59
60    lfs_file_seek(&lfs, &file, -size, LFS_SEEK_CUR) => pos;
61    lfs_file_read(&lfs, &file, buffer, size) => size;
62    memcmp(buffer, "kittycatcat", size) => 0;
63
64    lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1;
65    lfs_file_read(&lfs, &file, buffer, size) => size;
66    memcmp(buffer, "kittycatcat", size) => 0;
67
68    size = lfs_file_size(&lfs, &file);
69    lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size;
70
71    lfs_file_close(&lfs, &file) => 0;
72    lfs_unmount(&lfs) => 0;
73'''
74
75# simple file seek and write
76[cases.test_seek_write]
77defines = [
78    {COUNT=132, SKIP=4},
79    {COUNT=132, SKIP=128},
80    {COUNT=200, SKIP=10},
81    {COUNT=200, SKIP=100},
82    {COUNT=4,   SKIP=1},
83    {COUNT=4,   SKIP=2},
84]
85code = '''
86    lfs_t lfs;
87    lfs_format(&lfs, cfg) => 0;
88    lfs_mount(&lfs, cfg) => 0;
89    lfs_file_t file;
90    lfs_file_open(&lfs, &file, "kitty",
91            LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
92    size_t size = strlen("kittycatcat");
93    uint8_t buffer[1024];
94    memcpy(buffer, "kittycatcat", size);
95    for (int j = 0; j < COUNT; j++) {
96        lfs_file_write(&lfs, &file, buffer, size);
97    }
98    lfs_file_close(&lfs, &file) => 0;
99    lfs_unmount(&lfs) => 0;
100
101    lfs_mount(&lfs, cfg) => 0;
102    lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0;
103
104    lfs_soff_t pos = -1;
105    size = strlen("kittycatcat");
106    for (int i = 0; i < SKIP; i++) {
107        lfs_file_read(&lfs, &file, buffer, size) => size;
108        memcmp(buffer, "kittycatcat", size) => 0;
109        pos = lfs_file_tell(&lfs, &file);
110    }
111    assert(pos >= 0);
112
113    memcpy(buffer, "doggodogdog", size);
114    lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos;
115    lfs_file_write(&lfs, &file, buffer, size) => size;
116
117    lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos;
118    lfs_file_read(&lfs, &file, buffer, size) => size;
119    memcmp(buffer, "doggodogdog", size) => 0;
120
121    lfs_file_rewind(&lfs, &file) => 0;
122    lfs_file_read(&lfs, &file, buffer, size) => size;
123    memcmp(buffer, "kittycatcat", size) => 0;
124
125    lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos;
126    lfs_file_read(&lfs, &file, buffer, size) => size;
127    memcmp(buffer, "doggodogdog", size) => 0;
128
129    lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1;
130    lfs_file_read(&lfs, &file, buffer, size) => size;
131    memcmp(buffer, "kittycatcat", size) => 0;
132
133    size = lfs_file_size(&lfs, &file);
134    lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size;
135
136    lfs_file_close(&lfs, &file) => 0;
137    lfs_unmount(&lfs) => 0;
138'''
139
140# boundary seek and writes
141[cases.test_seek_boundary_write]
142defines.COUNT = 132
143code = '''
144    lfs_t lfs;
145    lfs_format(&lfs, cfg) => 0;
146    lfs_mount(&lfs, cfg) => 0;
147    lfs_file_t file;
148    lfs_file_open(&lfs, &file, "kitty",
149            LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
150    size_t size = strlen("kittycatcat");
151    uint8_t buffer[1024];
152    memcpy(buffer, "kittycatcat", size);
153    for (int j = 0; j < COUNT; j++) {
154        lfs_file_write(&lfs, &file, buffer, size);
155    }
156    lfs_file_close(&lfs, &file) => 0;
157    lfs_unmount(&lfs) => 0;
158
159    lfs_mount(&lfs, cfg) => 0;
160    lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0;
161
162    size = strlen("hedgehoghog");
163    const lfs_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019, 1441};
164
165    for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) {
166        lfs_soff_t off = offsets[i];
167        memcpy(buffer, "hedgehoghog", size);
168        lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off;
169        lfs_file_write(&lfs, &file, buffer, size) => size;
170        lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off;
171        lfs_file_read(&lfs, &file, buffer, size) => size;
172        memcmp(buffer, "hedgehoghog", size) => 0;
173
174        lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
175        lfs_file_read(&lfs, &file, buffer, size) => size;
176        memcmp(buffer, "kittycatcat", size) => 0;
177
178        lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off;
179        lfs_file_read(&lfs, &file, buffer, size) => size;
180        memcmp(buffer, "hedgehoghog", size) => 0;
181
182        lfs_file_sync(&lfs, &file) => 0;
183
184        lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
185        lfs_file_read(&lfs, &file, buffer, size) => size;
186        memcmp(buffer, "kittycatcat", size) => 0;
187
188        lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off;
189        lfs_file_read(&lfs, &file, buffer, size) => size;
190        memcmp(buffer, "hedgehoghog", size) => 0;
191    }
192
193    lfs_file_close(&lfs, &file) => 0;
194    lfs_unmount(&lfs) => 0;
195'''
196
197# out of bounds seek
198[cases.test_seek_out_of_bounds]
199defines = [
200    {COUNT=132, SKIP=4},
201    {COUNT=132, SKIP=128},
202    {COUNT=200, SKIP=10},
203    {COUNT=200, SKIP=100},
204    {COUNT=4,   SKIP=2},
205    {COUNT=4,   SKIP=3},
206]
207code = '''
208    lfs_t lfs;
209    lfs_format(&lfs, cfg) => 0;
210    lfs_mount(&lfs, cfg) => 0;
211    lfs_file_t file;
212    lfs_file_open(&lfs, &file, "kitty",
213            LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
214    size_t size = strlen("kittycatcat");
215    uint8_t buffer[1024];
216    memcpy(buffer, "kittycatcat", size);
217    for (int j = 0; j < COUNT; j++) {
218        lfs_file_write(&lfs, &file, buffer, size);
219    }
220    lfs_file_close(&lfs, &file) => 0;
221    lfs_unmount(&lfs) => 0;
222    lfs_mount(&lfs, cfg) => 0;
223    lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0;
224
225    size = strlen("kittycatcat");
226    lfs_file_size(&lfs, &file) => COUNT*size;
227    lfs_file_seek(&lfs, &file, (COUNT+SKIP)*size,
228            LFS_SEEK_SET) => (COUNT+SKIP)*size;
229    lfs_file_read(&lfs, &file, buffer, size) => 0;
230
231    memcpy(buffer, "porcupineee", size);
232    lfs_file_write(&lfs, &file, buffer, size) => size;
233
234    lfs_file_seek(&lfs, &file, (COUNT+SKIP)*size,
235            LFS_SEEK_SET) => (COUNT+SKIP)*size;
236    lfs_file_read(&lfs, &file, buffer, size) => size;
237    memcmp(buffer, "porcupineee", size) => 0;
238
239    lfs_file_seek(&lfs, &file, COUNT*size,
240            LFS_SEEK_SET) => COUNT*size;
241    lfs_file_read(&lfs, &file, buffer, size) => size;
242    memcmp(buffer, "\0\0\0\0\0\0\0\0\0\0\0", size) => 0;
243
244    lfs_file_seek(&lfs, &file, -((COUNT+SKIP)*size),
245            LFS_SEEK_CUR) => LFS_ERR_INVAL;
246    lfs_file_tell(&lfs, &file) => (COUNT+1)*size;
247
248    lfs_file_seek(&lfs, &file, -((COUNT+2*SKIP)*size),
249            LFS_SEEK_END) => LFS_ERR_INVAL;
250    lfs_file_tell(&lfs, &file) => (COUNT+1)*size;
251
252    lfs_file_close(&lfs, &file) => 0;
253    lfs_unmount(&lfs) => 0;
254'''
255
256# inline write and seek
257[cases.test_seek_inline_write]
258defines.SIZE = [2, 4, 128, 132]
259code = '''
260    lfs_t lfs;
261    lfs_format(&lfs, cfg) => 0;
262    lfs_mount(&lfs, cfg) => 0;
263    lfs_file_t file;
264    lfs_file_open(&lfs, &file, "tinykitty",
265            LFS_O_RDWR | LFS_O_CREAT) => 0;
266    int j = 0;
267    int k = 0;
268
269    uint8_t buffer[1024];
270    memcpy(buffer, "abcdefghijklmnopqrstuvwxyz", 26);
271    for (unsigned i = 0; i < SIZE; i++) {
272        lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1;
273        lfs_file_tell(&lfs, &file) => i+1;
274        lfs_file_size(&lfs, &file) => i+1;
275    }
276
277    lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
278    lfs_file_tell(&lfs, &file) => 0;
279    lfs_file_size(&lfs, &file) => SIZE;
280    for (unsigned i = 0; i < SIZE; i++) {
281        uint8_t c;
282        lfs_file_read(&lfs, &file, &c, 1) => 1;
283        c => buffer[k++ % 26];
284    }
285
286    lfs_file_sync(&lfs, &file) => 0;
287    lfs_file_tell(&lfs, &file) => SIZE;
288    lfs_file_size(&lfs, &file) => SIZE;
289
290    lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
291    for (unsigned i = 0; i < SIZE; i++) {
292        lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1;
293        lfs_file_tell(&lfs, &file) => i+1;
294        lfs_file_size(&lfs, &file) => SIZE;
295        lfs_file_sync(&lfs, &file) => 0;
296        lfs_file_tell(&lfs, &file) => i+1;
297        lfs_file_size(&lfs, &file) => SIZE;
298        if (i < SIZE-2) {
299            uint8_t c[3];
300            lfs_file_seek(&lfs, &file, -1, LFS_SEEK_CUR) => i;
301            lfs_file_read(&lfs, &file, &c, 3) => 3;
302            lfs_file_tell(&lfs, &file) => i+3;
303            lfs_file_size(&lfs, &file) => SIZE;
304            lfs_file_seek(&lfs, &file, i+1, LFS_SEEK_SET) => i+1;
305            lfs_file_tell(&lfs, &file) => i+1;
306            lfs_file_size(&lfs, &file) => SIZE;
307        }
308    }
309
310    lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
311    lfs_file_tell(&lfs, &file) => 0;
312    lfs_file_size(&lfs, &file) => SIZE;
313    for (unsigned i = 0; i < SIZE; i++) {
314        uint8_t c;
315        lfs_file_read(&lfs, &file, &c, 1) => 1;
316        c => buffer[k++ % 26];
317    }
318
319    lfs_file_sync(&lfs, &file) => 0;
320    lfs_file_tell(&lfs, &file) => SIZE;
321    lfs_file_size(&lfs, &file) => SIZE;
322
323    lfs_file_close(&lfs, &file) => 0;
324    lfs_unmount(&lfs) => 0;
325'''
326
327# file seek and write with power-loss
328[cases.test_seek_reentrant_write]
329# must be power-of-2 for quadratic probing to be exhaustive
330defines.COUNT = [4, 64, 128]
331reentrant = true
332code = '''
333    lfs_t lfs;
334    int err = lfs_mount(&lfs, cfg);
335    if (err) {
336        lfs_format(&lfs, cfg) => 0;
337        lfs_mount(&lfs, cfg) => 0;
338    }
339    lfs_file_t file;
340    uint8_t buffer[1024];
341    err = lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY);
342    assert(!err || err == LFS_ERR_NOENT);
343    if (!err) {
344        if (lfs_file_size(&lfs, &file) != 0) {
345            lfs_file_size(&lfs, &file) => 11*COUNT;
346            for (int j = 0; j < COUNT; j++) {
347                memset(buffer, 0, 11+1);
348                lfs_file_read(&lfs, &file, buffer, 11) => 11;
349                assert(memcmp(buffer, "kittycatcat", 11) == 0 ||
350                       memcmp(buffer, "doggodogdog", 11) == 0);
351            }
352        }
353        lfs_file_close(&lfs, &file) => 0;
354    }
355
356    lfs_file_open(&lfs, &file, "kitty", LFS_O_WRONLY | LFS_O_CREAT) => 0;
357    if (lfs_file_size(&lfs, &file) == 0) {
358        for (int j = 0; j < COUNT; j++) {
359            strcpy((char*)buffer, "kittycatcat");
360            size_t size = strlen((char*)buffer);
361            lfs_file_write(&lfs, &file, buffer, size) => size;
362        }
363    }
364    lfs_file_close(&lfs, &file) => 0;
365
366    strcpy((char*)buffer, "doggodogdog");
367    size_t size = strlen((char*)buffer);
368
369    lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0;
370    lfs_file_size(&lfs, &file) => COUNT*size;
371    // seek and write using quadratic probing to touch all
372    // 11-byte words in the file
373    lfs_off_t off = 0;
374    for (int j = 0; j < COUNT; j++) {
375        off = (5*off + 1) % COUNT;
376        lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size;
377        lfs_file_read(&lfs, &file, buffer, size) => size;
378        assert(memcmp(buffer, "kittycatcat", size) == 0 ||
379               memcmp(buffer, "doggodogdog", size) == 0);
380        if (memcmp(buffer, "doggodogdog", size) != 0) {
381            lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size;
382            strcpy((char*)buffer, "doggodogdog");
383            lfs_file_write(&lfs, &file, buffer, size) => size;
384            lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size;
385            lfs_file_read(&lfs, &file, buffer, size) => size;
386            assert(memcmp(buffer, "doggodogdog", size) == 0);
387            lfs_file_sync(&lfs, &file) => 0;
388            lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size;
389            lfs_file_read(&lfs, &file, buffer, size) => size;
390            assert(memcmp(buffer, "doggodogdog", size) == 0);
391        }
392    }
393    lfs_file_close(&lfs, &file) => 0;
394
395    lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0;
396    lfs_file_size(&lfs, &file) => COUNT*size;
397    for (int j = 0; j < COUNT; j++) {
398        lfs_file_read(&lfs, &file, buffer, size) => size;
399        assert(memcmp(buffer, "doggodogdog", size) == 0);
400    }
401    lfs_file_close(&lfs, &file) => 0;
402    lfs_unmount(&lfs) => 0;
403'''
404