1[[case]] # simple truncate
2define.MEDIUMSIZE = [32, 2048]
3define.LARGESIZE = 8192
4code = '''
5    lfs_format(&lfs, &cfg) => 0;
6    lfs_mount(&lfs, &cfg) => 0;
7    lfs_file_open(&lfs, &file, "baldynoop",
8            LFS_O_WRONLY | LFS_O_CREAT) => 0;
9
10    strcpy((char*)buffer, "hair");
11    size = strlen((char*)buffer);
12    for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
13        lfs_file_write(&lfs, &file, buffer, size) => size;
14    }
15    lfs_file_size(&lfs, &file) => LARGESIZE;
16
17    lfs_file_close(&lfs, &file) => 0;
18    lfs_unmount(&lfs) => 0;
19
20    lfs_mount(&lfs, &cfg) => 0;
21    lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0;
22    lfs_file_size(&lfs, &file) => LARGESIZE;
23
24    lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0;
25    lfs_file_size(&lfs, &file) => MEDIUMSIZE;
26
27    lfs_file_close(&lfs, &file) => 0;
28    lfs_unmount(&lfs) => 0;
29
30    lfs_mount(&lfs, &cfg) => 0;
31    lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDONLY) => 0;
32    lfs_file_size(&lfs, &file) => MEDIUMSIZE;
33
34    size = strlen("hair");
35    for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
36        lfs_file_read(&lfs, &file, buffer, size) => size;
37        memcmp(buffer, "hair", size) => 0;
38    }
39    lfs_file_read(&lfs, &file, buffer, size) => 0;
40
41    lfs_file_close(&lfs, &file) => 0;
42    lfs_unmount(&lfs) => 0;
43'''
44
45[[case]] # truncate and read
46define.MEDIUMSIZE = [32, 2048]
47define.LARGESIZE = 8192
48code = '''
49    lfs_format(&lfs, &cfg) => 0;
50    lfs_mount(&lfs, &cfg) => 0;
51    lfs_file_open(&lfs, &file, "baldyread",
52            LFS_O_WRONLY | LFS_O_CREAT) => 0;
53
54    strcpy((char*)buffer, "hair");
55    size = strlen((char*)buffer);
56    for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
57        lfs_file_write(&lfs, &file, buffer, size) => size;
58    }
59    lfs_file_size(&lfs, &file) => LARGESIZE;
60
61    lfs_file_close(&lfs, &file) => 0;
62    lfs_unmount(&lfs) => 0;
63
64    lfs_mount(&lfs, &cfg) => 0;
65    lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDWR) => 0;
66    lfs_file_size(&lfs, &file) => LARGESIZE;
67
68    lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0;
69    lfs_file_size(&lfs, &file) => MEDIUMSIZE;
70
71    size = strlen("hair");
72    for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
73        lfs_file_read(&lfs, &file, buffer, size) => size;
74        memcmp(buffer, "hair", size) => 0;
75    }
76    lfs_file_read(&lfs, &file, buffer, size) => 0;
77
78    lfs_file_close(&lfs, &file) => 0;
79    lfs_unmount(&lfs) => 0;
80
81    lfs_mount(&lfs, &cfg) => 0;
82    lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDONLY) => 0;
83    lfs_file_size(&lfs, &file) => MEDIUMSIZE;
84
85    size = strlen("hair");
86    for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
87        lfs_file_read(&lfs, &file, buffer, size) => size;
88        memcmp(buffer, "hair", size) => 0;
89    }
90    lfs_file_read(&lfs, &file, buffer, size) => 0;
91
92    lfs_file_close(&lfs, &file) => 0;
93    lfs_unmount(&lfs) => 0;
94'''
95
96[[case]] # write, truncate, and read
97code = '''
98    lfs_format(&lfs, &cfg) => 0;
99    lfs_mount(&lfs, &cfg) => 0;
100    lfs_file_open(&lfs, &file, "sequence",
101            LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0;
102
103    size = lfs_min(lfs.cfg->cache_size, sizeof(buffer)/2);
104    lfs_size_t qsize = size / 4;
105    uint8_t *wb = buffer;
106    uint8_t *rb = buffer + size;
107    for (lfs_off_t j = 0; j < size; ++j) {
108        wb[j] = j;
109    }
110
111    /* Spread sequence over size */
112    lfs_file_write(&lfs, &file, wb, size) => size;
113    lfs_file_size(&lfs, &file) => size;
114    lfs_file_tell(&lfs, &file) => size;
115
116    lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
117    lfs_file_tell(&lfs, &file) => 0;
118
119    /* Chop off the last quarter */
120    lfs_size_t trunc = size - qsize;
121    lfs_file_truncate(&lfs, &file, trunc) => 0;
122    lfs_file_tell(&lfs, &file) => 0;
123    lfs_file_size(&lfs, &file) => trunc;
124
125    /* Read should produce first 3/4 */
126    lfs_file_read(&lfs, &file, rb, size) => trunc;
127    memcmp(rb, wb, trunc) => 0;
128
129    /* Move to 1/4 */
130    lfs_file_size(&lfs, &file) => trunc;
131    lfs_file_seek(&lfs, &file, qsize, LFS_SEEK_SET) => qsize;
132    lfs_file_tell(&lfs, &file) => qsize;
133
134    /* Chop to 1/2 */
135    trunc -= qsize;
136    lfs_file_truncate(&lfs, &file, trunc) => 0;
137    lfs_file_tell(&lfs, &file) => qsize;
138    lfs_file_size(&lfs, &file) => trunc;
139
140    /* Read should produce second quarter */
141    lfs_file_read(&lfs, &file, rb, size) => trunc - qsize;
142    memcmp(rb, wb + qsize, trunc - qsize) => 0;
143
144    lfs_file_close(&lfs, &file) => 0;
145    lfs_unmount(&lfs) => 0;
146'''
147
148[[case]] # truncate and write
149define.MEDIUMSIZE = [32, 2048]
150define.LARGESIZE = 8192
151code = '''
152    lfs_format(&lfs, &cfg) => 0;
153    lfs_mount(&lfs, &cfg) => 0;
154    lfs_file_open(&lfs, &file, "baldywrite",
155            LFS_O_WRONLY | LFS_O_CREAT) => 0;
156
157    strcpy((char*)buffer, "hair");
158    size = strlen((char*)buffer);
159    for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
160        lfs_file_write(&lfs, &file, buffer, size) => size;
161    }
162    lfs_file_size(&lfs, &file) => LARGESIZE;
163
164    lfs_file_close(&lfs, &file) => 0;
165    lfs_unmount(&lfs) => 0;
166
167    lfs_mount(&lfs, &cfg) => 0;
168    lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDWR) => 0;
169    lfs_file_size(&lfs, &file) => LARGESIZE;
170
171    lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0;
172    lfs_file_size(&lfs, &file) => MEDIUMSIZE;
173
174    strcpy((char*)buffer, "bald");
175    size = strlen((char*)buffer);
176    for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
177        lfs_file_write(&lfs, &file, buffer, size) => size;
178    }
179    lfs_file_size(&lfs, &file) => MEDIUMSIZE;
180
181    lfs_file_close(&lfs, &file) => 0;
182    lfs_unmount(&lfs) => 0;
183
184    lfs_mount(&lfs, &cfg) => 0;
185    lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDONLY) => 0;
186    lfs_file_size(&lfs, &file) => MEDIUMSIZE;
187
188    size = strlen("bald");
189    for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
190        lfs_file_read(&lfs, &file, buffer, size) => size;
191        memcmp(buffer, "bald", size) => 0;
192    }
193    lfs_file_read(&lfs, &file, buffer, size) => 0;
194
195    lfs_file_close(&lfs, &file) => 0;
196    lfs_unmount(&lfs) => 0;
197'''
198
199[[case]] # truncate write under powerloss
200define.SMALLSIZE = [4, 512]
201define.MEDIUMSIZE = [32, 1024]
202define.LARGESIZE = 2048
203reentrant = true
204code = '''
205    err = lfs_mount(&lfs, &cfg);
206    if (err) {
207        lfs_format(&lfs, &cfg) => 0;
208        lfs_mount(&lfs, &cfg) => 0;
209    }
210    err = lfs_file_open(&lfs, &file, "baldy", LFS_O_RDONLY);
211    assert(!err || err == LFS_ERR_NOENT);
212    if (!err) {
213        size = lfs_file_size(&lfs, &file);
214        assert(size == 0 ||
215                size == LARGESIZE ||
216                size == MEDIUMSIZE ||
217                size == SMALLSIZE);
218        for (lfs_off_t j = 0; j < size; j += 4) {
219            lfs_file_read(&lfs, &file, buffer, 4) => 4;
220            assert(memcmp(buffer, "hair", 4) == 0 ||
221                   memcmp(buffer, "bald", 4) == 0 ||
222                   memcmp(buffer, "comb", 4) == 0);
223        }
224        lfs_file_close(&lfs, &file) => 0;
225    }
226
227    lfs_file_open(&lfs, &file, "baldy",
228            LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
229    lfs_file_size(&lfs, &file) => 0;
230    strcpy((char*)buffer, "hair");
231    size = strlen((char*)buffer);
232    for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
233        lfs_file_write(&lfs, &file, buffer, size) => size;
234    }
235    lfs_file_size(&lfs, &file) => LARGESIZE;
236    lfs_file_close(&lfs, &file) => 0;
237
238    lfs_file_open(&lfs, &file, "baldy", LFS_O_RDWR) => 0;
239    lfs_file_size(&lfs, &file) => LARGESIZE;
240    lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0;
241    lfs_file_size(&lfs, &file) => MEDIUMSIZE;
242    strcpy((char*)buffer, "bald");
243    size = strlen((char*)buffer);
244    for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
245        lfs_file_write(&lfs, &file, buffer, size) => size;
246    }
247    lfs_file_size(&lfs, &file) => MEDIUMSIZE;
248    lfs_file_close(&lfs, &file) => 0;
249
250    lfs_file_open(&lfs, &file, "baldy", LFS_O_RDWR) => 0;
251    lfs_file_size(&lfs, &file) => MEDIUMSIZE;
252    lfs_file_truncate(&lfs, &file, SMALLSIZE) => 0;
253    lfs_file_size(&lfs, &file) => SMALLSIZE;
254    strcpy((char*)buffer, "comb");
255    size = strlen((char*)buffer);
256    for (lfs_off_t j = 0; j < SMALLSIZE; j += size) {
257        lfs_file_write(&lfs, &file, buffer, size) => size;
258    }
259    lfs_file_size(&lfs, &file) => SMALLSIZE;
260    lfs_file_close(&lfs, &file) => 0;
261
262    lfs_unmount(&lfs) => 0;
263'''
264
265[[case]] # more aggressive general truncation tests
266define.CONFIG = 'range(6)'
267define.SMALLSIZE = 32
268define.MEDIUMSIZE = 2048
269define.LARGESIZE = 8192
270code = '''
271    #define COUNT 5
272    const struct {
273        lfs_off_t startsizes[COUNT];
274        lfs_off_t startseeks[COUNT];
275        lfs_off_t hotsizes[COUNT];
276        lfs_off_t coldsizes[COUNT];
277    } configs[] = {
278        // cold shrinking
279        {{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE},
280         {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE},
281         {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE},
282         {          0,   SMALLSIZE,  MEDIUMSIZE,   LARGESIZE, 2*LARGESIZE}},
283        // cold expanding
284        {{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE},
285         {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE},
286         {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE},
287         {          0,   SMALLSIZE,  MEDIUMSIZE,   LARGESIZE, 2*LARGESIZE}},
288        // warm shrinking truncate
289        {{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE},
290         {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE},
291         {          0,   SMALLSIZE,  MEDIUMSIZE,   LARGESIZE, 2*LARGESIZE},
292         {          0,           0,           0,           0,           0}},
293        // warm expanding truncate
294        {{          0,   SMALLSIZE,  MEDIUMSIZE,   LARGESIZE, 2*LARGESIZE},
295         {          0,   SMALLSIZE,  MEDIUMSIZE,   LARGESIZE, 2*LARGESIZE},
296         {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE},
297         {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}},
298        // mid-file shrinking truncate
299        {{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE},
300         {  LARGESIZE,   LARGESIZE,   LARGESIZE,   LARGESIZE,   LARGESIZE},
301         {          0,   SMALLSIZE,  MEDIUMSIZE,   LARGESIZE, 2*LARGESIZE},
302         {          0,           0,           0,           0,           0}},
303        // mid-file expanding truncate
304        {{          0,   SMALLSIZE,   MEDIUMSIZE,  LARGESIZE, 2*LARGESIZE},
305         {          0,           0,   SMALLSIZE,  MEDIUMSIZE,   LARGESIZE},
306         {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE},
307         {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}},
308    };
309
310    const lfs_off_t *startsizes = configs[CONFIG].startsizes;
311    const lfs_off_t *startseeks = configs[CONFIG].startseeks;
312    const lfs_off_t *hotsizes   = configs[CONFIG].hotsizes;
313    const lfs_off_t *coldsizes  = configs[CONFIG].coldsizes;
314
315    lfs_format(&lfs, &cfg) => 0;
316    lfs_mount(&lfs, &cfg) => 0;
317
318    for (unsigned i = 0; i < COUNT; i++) {
319        sprintf(path, "hairyhead%d", i);
320        lfs_file_open(&lfs, &file, path,
321                LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
322
323        strcpy((char*)buffer, "hair");
324        size = strlen((char*)buffer);
325        for (lfs_off_t j = 0; j < startsizes[i]; j += size) {
326            lfs_file_write(&lfs, &file, buffer, size) => size;
327        }
328        lfs_file_size(&lfs, &file) => startsizes[i];
329
330        if (startseeks[i] != startsizes[i]) {
331            lfs_file_seek(&lfs, &file,
332                    startseeks[i], LFS_SEEK_SET) => startseeks[i];
333        }
334
335        lfs_file_truncate(&lfs, &file, hotsizes[i]) => 0;
336        lfs_file_size(&lfs, &file) => hotsizes[i];
337
338        lfs_file_close(&lfs, &file) => 0;
339    }
340
341    lfs_unmount(&lfs) => 0;
342
343    lfs_mount(&lfs, &cfg) => 0;
344
345    for (unsigned i = 0; i < COUNT; i++) {
346        sprintf(path, "hairyhead%d", i);
347        lfs_file_open(&lfs, &file, path, LFS_O_RDWR) => 0;
348        lfs_file_size(&lfs, &file) => hotsizes[i];
349
350        size = strlen("hair");
351        lfs_off_t j = 0;
352        for (; j < startsizes[i] && j < hotsizes[i]; j += size) {
353            lfs_file_read(&lfs, &file, buffer, size) => size;
354            memcmp(buffer, "hair", size) => 0;
355        }
356
357        for (; j < hotsizes[i]; j += size) {
358            lfs_file_read(&lfs, &file, buffer, size) => size;
359            memcmp(buffer, "\0\0\0\0", size) => 0;
360        }
361
362        lfs_file_truncate(&lfs, &file, coldsizes[i]) => 0;
363        lfs_file_size(&lfs, &file) => coldsizes[i];
364
365        lfs_file_close(&lfs, &file) => 0;
366    }
367
368    lfs_unmount(&lfs) => 0;
369
370    lfs_mount(&lfs, &cfg) => 0;
371
372    for (unsigned i = 0; i < COUNT; i++) {
373        sprintf(path, "hairyhead%d", i);
374        lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
375        lfs_file_size(&lfs, &file) => coldsizes[i];
376
377        size = strlen("hair");
378        lfs_off_t j = 0;
379        for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i];
380                j += size) {
381            lfs_file_read(&lfs, &file, buffer, size) => size;
382            memcmp(buffer, "hair", size) => 0;
383        }
384
385        for (; j < coldsizes[i]; j += size) {
386            lfs_file_read(&lfs, &file, buffer, size) => size;
387            memcmp(buffer, "\0\0\0\0", size) => 0;
388        }
389
390        lfs_file_close(&lfs, &file) => 0;
391    }
392
393    lfs_unmount(&lfs) => 0;
394'''
395