1[[case]] # move file
2code = '''
3    lfs_format(&lfs, &cfg) => 0;
4    lfs_mount(&lfs, &cfg) => 0;
5    lfs_mkdir(&lfs, "a") => 0;
6    lfs_mkdir(&lfs, "b") => 0;
7    lfs_mkdir(&lfs, "c") => 0;
8    lfs_mkdir(&lfs, "d") => 0;
9    lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0;
10    lfs_file_write(&lfs, &file, "hola\n", 5) => 5;
11    lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8;
12    lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6;
13    lfs_file_close(&lfs, &file) => 0;
14    lfs_unmount(&lfs) => 0;
15
16    lfs_mount(&lfs, &cfg) => 0;
17    lfs_rename(&lfs, "a/hello", "c/hello") => 0;
18    lfs_unmount(&lfs) => 0;
19
20    lfs_mount(&lfs, &cfg) => 0;
21    lfs_dir_open(&lfs, &dir, "a") => 0;
22    lfs_dir_read(&lfs, &dir, &info) => 1;
23    assert(strcmp(info.name, ".") == 0);
24    assert(info.type == LFS_TYPE_DIR);
25    lfs_dir_read(&lfs, &dir, &info) => 1;
26    assert(strcmp(info.name, "..") == 0);
27    assert(info.type == LFS_TYPE_DIR);
28    lfs_dir_read(&lfs, &dir, &info) => 0;
29    lfs_dir_close(&lfs, &dir) => 0;
30    lfs_dir_open(&lfs, &dir, "c") => 0;
31    lfs_dir_read(&lfs, &dir, &info) => 1;
32    assert(strcmp(info.name, ".") == 0);
33    assert(info.type == LFS_TYPE_DIR);
34    lfs_dir_read(&lfs, &dir, &info) => 1;
35    assert(strcmp(info.name, "..") == 0);
36    assert(info.type == LFS_TYPE_DIR);
37    lfs_dir_read(&lfs, &dir, &info) => 1;
38    assert(strcmp(info.name, "hello") == 0);
39    assert(info.type == LFS_TYPE_REG);
40    assert(info.size == 5+8+6);
41    lfs_dir_read(&lfs, &dir, &info) => 0;
42    lfs_dir_close(&lfs, &dir) => 0;
43
44    lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
45    lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
46    lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => 0;
47    lfs_file_read(&lfs, &file, buffer, 5) => 5;
48    memcmp(buffer, "hola\n", 5) => 0;
49    lfs_file_read(&lfs, &file, buffer, 8) => 8;
50    memcmp(buffer, "bonjour\n", 8) => 0;
51    lfs_file_read(&lfs, &file, buffer, 6) => 6;
52    memcmp(buffer, "ohayo\n", 6) => 0;
53    lfs_file_close(&lfs, &file) => 0;
54    lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
55    lfs_unmount(&lfs) => 0;
56'''
57
58[[case]] # noop move, yes this is legal
59code = '''
60    lfs_format(&lfs, &cfg) => 0;
61    lfs_mount(&lfs, &cfg) => 0;
62    lfs_mkdir(&lfs, "hi") => 0;
63    lfs_rename(&lfs, "hi", "hi") => 0;
64    lfs_mkdir(&lfs, "hi/hi") => 0;
65    lfs_rename(&lfs, "hi/hi", "hi/hi") => 0;
66    lfs_mkdir(&lfs, "hi/hi/hi") => 0;
67    lfs_rename(&lfs, "hi/hi/hi", "hi/hi/hi") => 0;
68    lfs_stat(&lfs, "hi/hi/hi", &info) => 0;
69    assert(strcmp(info.name, "hi") == 0);
70    assert(info.type == LFS_TYPE_DIR);
71    lfs_unmount(&lfs) => 0;
72'''
73
74[[case]] # move file corrupt source
75in = "lfs.c"
76code = '''
77    lfs_format(&lfs, &cfg) => 0;
78    lfs_mount(&lfs, &cfg) => 0;
79    lfs_mkdir(&lfs, "a") => 0;
80    lfs_mkdir(&lfs, "b") => 0;
81    lfs_mkdir(&lfs, "c") => 0;
82    lfs_mkdir(&lfs, "d") => 0;
83    lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0;
84    lfs_file_write(&lfs, &file, "hola\n", 5) => 5;
85    lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8;
86    lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6;
87    lfs_file_close(&lfs, &file) => 0;
88    lfs_unmount(&lfs) => 0;
89
90    lfs_mount(&lfs, &cfg) => 0;
91    lfs_rename(&lfs, "a/hello", "c/hello") => 0;
92    lfs_unmount(&lfs) => 0;
93
94    // corrupt the source
95    lfs_mount(&lfs, &cfg) => 0;
96    lfs_dir_open(&lfs, &dir, "a") => 0;
97    lfs_block_t block = dir.m.pair[0];
98    lfs_dir_close(&lfs, &dir) => 0;
99    lfs_unmount(&lfs) => 0;
100    uint8_t bbuffer[LFS_BLOCK_SIZE];
101    cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
102    int off = LFS_BLOCK_SIZE-1;
103    while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
104        off -= 1;
105    }
106    memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
107    cfg.erase(&cfg, block) => 0;
108    cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
109    cfg.sync(&cfg) => 0;
110
111    lfs_mount(&lfs, &cfg) => 0;
112    lfs_dir_open(&lfs, &dir, "a") => 0;
113    lfs_dir_read(&lfs, &dir, &info) => 1;
114    assert(strcmp(info.name, ".") == 0);
115    assert(info.type == LFS_TYPE_DIR);
116    lfs_dir_read(&lfs, &dir, &info) => 1;
117    assert(strcmp(info.name, "..") == 0);
118    assert(info.type == LFS_TYPE_DIR);
119    lfs_dir_read(&lfs, &dir, &info) => 0;
120    lfs_dir_close(&lfs, &dir) => 0;
121    lfs_dir_open(&lfs, &dir, "c") => 0;
122    lfs_dir_read(&lfs, &dir, &info) => 1;
123    assert(strcmp(info.name, ".") == 0);
124    assert(info.type == LFS_TYPE_DIR);
125    lfs_dir_read(&lfs, &dir, &info) => 1;
126    assert(strcmp(info.name, "..") == 0);
127    assert(info.type == LFS_TYPE_DIR);
128    lfs_dir_read(&lfs, &dir, &info) => 1;
129    assert(strcmp(info.name, "hello") == 0);
130    assert(info.type == LFS_TYPE_REG);
131    assert(info.size == 5+8+6);
132    lfs_dir_read(&lfs, &dir, &info) => 0;
133    lfs_dir_close(&lfs, &dir) => 0;
134
135    lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
136    lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
137    lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => 0;
138    lfs_file_read(&lfs, &file, buffer, 5) => 5;
139    memcmp(buffer, "hola\n", 5) => 0;
140    lfs_file_read(&lfs, &file, buffer, 8) => 8;
141    memcmp(buffer, "bonjour\n", 8) => 0;
142    lfs_file_read(&lfs, &file, buffer, 6) => 6;
143    memcmp(buffer, "ohayo\n", 6) => 0;
144    lfs_file_close(&lfs, &file) => 0;
145    lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
146    lfs_unmount(&lfs) => 0;
147'''
148
149[[case]] # move file corrupt source and dest
150in = "lfs.c"
151if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit
152code = '''
153    lfs_format(&lfs, &cfg) => 0;
154    lfs_mount(&lfs, &cfg) => 0;
155    lfs_mkdir(&lfs, "a") => 0;
156    lfs_mkdir(&lfs, "b") => 0;
157    lfs_mkdir(&lfs, "c") => 0;
158    lfs_mkdir(&lfs, "d") => 0;
159    lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0;
160    lfs_file_write(&lfs, &file, "hola\n", 5) => 5;
161    lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8;
162    lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6;
163    lfs_file_close(&lfs, &file) => 0;
164    lfs_unmount(&lfs) => 0;
165
166    lfs_mount(&lfs, &cfg) => 0;
167    lfs_rename(&lfs, "a/hello", "c/hello") => 0;
168    lfs_unmount(&lfs) => 0;
169
170    // corrupt the source
171    lfs_mount(&lfs, &cfg) => 0;
172    lfs_dir_open(&lfs, &dir, "a") => 0;
173    lfs_block_t block = dir.m.pair[0];
174    lfs_dir_close(&lfs, &dir) => 0;
175    lfs_unmount(&lfs) => 0;
176    uint8_t bbuffer[LFS_BLOCK_SIZE];
177    cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
178    int off = LFS_BLOCK_SIZE-1;
179    while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
180        off -= 1;
181    }
182    memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
183    cfg.erase(&cfg, block) => 0;
184    cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
185    cfg.sync(&cfg) => 0;
186
187    // corrupt the destination
188    lfs_mount(&lfs, &cfg) => 0;
189    lfs_dir_open(&lfs, &dir, "c") => 0;
190    block = dir.m.pair[0];
191    lfs_dir_close(&lfs, &dir) => 0;
192    lfs_unmount(&lfs) => 0;
193    cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
194    off = LFS_BLOCK_SIZE-1;
195    while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
196        off -= 1;
197    }
198    memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
199    cfg.erase(&cfg, block) => 0;
200    cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
201    cfg.sync(&cfg) => 0;
202
203    lfs_mount(&lfs, &cfg) => 0;
204    lfs_dir_open(&lfs, &dir, "a") => 0;
205    lfs_dir_read(&lfs, &dir, &info) => 1;
206    assert(strcmp(info.name, ".") == 0);
207    assert(info.type == LFS_TYPE_DIR);
208    lfs_dir_read(&lfs, &dir, &info) => 1;
209    assert(strcmp(info.name, "..") == 0);
210    assert(info.type == LFS_TYPE_DIR);
211    lfs_dir_read(&lfs, &dir, &info) => 1;
212    assert(strcmp(info.name, "hello") == 0);
213    assert(info.type == LFS_TYPE_REG);
214    assert(info.size == 5+8+6);
215    lfs_dir_read(&lfs, &dir, &info) => 0;
216    lfs_dir_close(&lfs, &dir) => 0;
217    lfs_dir_open(&lfs, &dir, "c") => 0;
218    lfs_dir_read(&lfs, &dir, &info) => 1;
219    assert(strcmp(info.name, ".") == 0);
220    assert(info.type == LFS_TYPE_DIR);
221    lfs_dir_read(&lfs, &dir, &info) => 1;
222    assert(strcmp(info.name, "..") == 0);
223    assert(info.type == LFS_TYPE_DIR);
224    lfs_dir_read(&lfs, &dir, &info) => 0;
225    lfs_dir_close(&lfs, &dir) => 0;
226
227    lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => 0;
228    lfs_file_read(&lfs, &file, buffer, 5) => 5;
229    memcmp(buffer, "hola\n", 5) => 0;
230    lfs_file_read(&lfs, &file, buffer, 8) => 8;
231    memcmp(buffer, "bonjour\n", 8) => 0;
232    lfs_file_read(&lfs, &file, buffer, 6) => 6;
233    memcmp(buffer, "ohayo\n", 6) => 0;
234    lfs_file_close(&lfs, &file) => 0;
235    lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
236    lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
237    lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
238    lfs_unmount(&lfs) => 0;
239'''
240
241[[case]] # move file after corrupt
242in = "lfs.c"
243if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit
244code = '''
245    lfs_format(&lfs, &cfg) => 0;
246    lfs_mount(&lfs, &cfg) => 0;
247    lfs_mkdir(&lfs, "a") => 0;
248    lfs_mkdir(&lfs, "b") => 0;
249    lfs_mkdir(&lfs, "c") => 0;
250    lfs_mkdir(&lfs, "d") => 0;
251    lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0;
252    lfs_file_write(&lfs, &file, "hola\n", 5) => 5;
253    lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8;
254    lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6;
255    lfs_file_close(&lfs, &file) => 0;
256    lfs_unmount(&lfs) => 0;
257
258    lfs_mount(&lfs, &cfg) => 0;
259    lfs_rename(&lfs, "a/hello", "c/hello") => 0;
260    lfs_unmount(&lfs) => 0;
261
262    // corrupt the source
263    lfs_mount(&lfs, &cfg) => 0;
264    lfs_dir_open(&lfs, &dir, "a") => 0;
265    lfs_block_t block = dir.m.pair[0];
266    lfs_dir_close(&lfs, &dir) => 0;
267    lfs_unmount(&lfs) => 0;
268    uint8_t bbuffer[LFS_BLOCK_SIZE];
269    cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
270    int off = LFS_BLOCK_SIZE-1;
271    while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
272        off -= 1;
273    }
274    memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
275    cfg.erase(&cfg, block) => 0;
276    cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
277    cfg.sync(&cfg) => 0;
278
279    // corrupt the destination
280    lfs_mount(&lfs, &cfg) => 0;
281    lfs_dir_open(&lfs, &dir, "c") => 0;
282    block = dir.m.pair[0];
283    lfs_dir_close(&lfs, &dir) => 0;
284    lfs_unmount(&lfs) => 0;
285    cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
286    off = LFS_BLOCK_SIZE-1;
287    while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
288        off -= 1;
289    }
290    memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
291    cfg.erase(&cfg, block) => 0;
292    cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
293    cfg.sync(&cfg) => 0;
294
295    // continue move
296    lfs_mount(&lfs, &cfg) => 0;
297    lfs_rename(&lfs, "a/hello", "c/hello") => 0;
298    lfs_unmount(&lfs) => 0;
299
300    lfs_mount(&lfs, &cfg) => 0;
301    lfs_dir_open(&lfs, &dir, "a") => 0;
302    lfs_dir_read(&lfs, &dir, &info) => 1;
303    assert(strcmp(info.name, ".") == 0);
304    assert(info.type == LFS_TYPE_DIR);
305    lfs_dir_read(&lfs, &dir, &info) => 1;
306    assert(strcmp(info.name, "..") == 0);
307    assert(info.type == LFS_TYPE_DIR);
308    lfs_dir_read(&lfs, &dir, &info) => 0;
309    lfs_dir_close(&lfs, &dir) => 0;
310    lfs_dir_open(&lfs, &dir, "c") => 0;
311    lfs_dir_read(&lfs, &dir, &info) => 1;
312    assert(strcmp(info.name, ".") == 0);
313    assert(info.type == LFS_TYPE_DIR);
314    lfs_dir_read(&lfs, &dir, &info) => 1;
315    assert(strcmp(info.name, "..") == 0);
316    assert(info.type == LFS_TYPE_DIR);
317    lfs_dir_read(&lfs, &dir, &info) => 1;
318    assert(strcmp(info.name, "hello") == 0);
319    assert(info.type == LFS_TYPE_REG);
320    assert(info.size == 5+8+6);
321    lfs_dir_read(&lfs, &dir, &info) => 0;
322    lfs_dir_close(&lfs, &dir) => 0;
323
324    lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
325    lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
326    lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => 0;
327    lfs_file_read(&lfs, &file, buffer, 5) => 5;
328    memcmp(buffer, "hola\n", 5) => 0;
329    lfs_file_read(&lfs, &file, buffer, 8) => 8;
330    memcmp(buffer, "bonjour\n", 8) => 0;
331    lfs_file_read(&lfs, &file, buffer, 6) => 6;
332    memcmp(buffer, "ohayo\n", 6) => 0;
333    lfs_file_close(&lfs, &file) => 0;
334    lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
335    lfs_unmount(&lfs) => 0;
336'''
337
338[[case]] # simple reentrant move file
339reentrant = true
340code = '''
341    err = lfs_mount(&lfs, &cfg);
342    if (err) {
343        lfs_format(&lfs, &cfg) => 0;
344        lfs_mount(&lfs, &cfg) => 0;
345    }
346    err = lfs_mkdir(&lfs, "a");
347    assert(!err || err == LFS_ERR_EXIST);
348    err = lfs_mkdir(&lfs, "b");
349    assert(!err || err == LFS_ERR_EXIST);
350    err = lfs_mkdir(&lfs, "c");
351    assert(!err || err == LFS_ERR_EXIST);
352    err = lfs_mkdir(&lfs, "d");
353    assert(!err || err == LFS_ERR_EXIST);
354    lfs_unmount(&lfs) => 0;
355
356    while (true) {
357        lfs_mount(&lfs, &cfg) => 0;
358        // there should never exist _2_ hello files
359        int count = 0;
360        if (lfs_stat(&lfs, "a/hello", &info) == 0) {
361            assert(strcmp(info.name, "hello") == 0);
362            assert(info.type == LFS_TYPE_REG);
363            assert(info.size == 5+8+6 || info.size == 0);
364            count += 1;
365        }
366        if (lfs_stat(&lfs, "b/hello", &info) == 0) {
367            assert(strcmp(info.name, "hello") == 0);
368            assert(info.type == LFS_TYPE_REG);
369            assert(info.size == 5+8+6);
370            count += 1;
371        }
372        if (lfs_stat(&lfs, "c/hello", &info) == 0) {
373            assert(strcmp(info.name, "hello") == 0);
374            assert(info.type == LFS_TYPE_REG);
375            assert(info.size == 5+8+6);
376            count += 1;
377        }
378        if (lfs_stat(&lfs, "d/hello", &info) == 0) {
379            assert(strcmp(info.name, "hello") == 0);
380            assert(info.type == LFS_TYPE_REG);
381            assert(info.size == 5+8+6);
382            count += 1;
383        }
384        assert(count <= 1);
385        lfs_unmount(&lfs) => 0;
386
387        lfs_mount(&lfs, &cfg) => 0;
388        if (lfs_stat(&lfs, "a/hello", &info) == 0 && info.size > 0) {
389            lfs_rename(&lfs, "a/hello", "b/hello") => 0;
390        } else if (lfs_stat(&lfs, "b/hello", &info) == 0) {
391            lfs_rename(&lfs, "b/hello", "c/hello") => 0;
392        } else if (lfs_stat(&lfs, "c/hello", &info) == 0) {
393            lfs_rename(&lfs, "c/hello", "d/hello") => 0;
394        } else if (lfs_stat(&lfs, "d/hello", &info) == 0) {
395            // success
396            lfs_unmount(&lfs) => 0;
397            break;
398        } else {
399            // create file
400            lfs_file_open(&lfs, &file, "a/hello",
401                    LFS_O_WRONLY | LFS_O_CREAT) => 0;
402            lfs_file_write(&lfs, &file, "hola\n", 5) => 5;
403            lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8;
404            lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6;
405            lfs_file_close(&lfs, &file) => 0;
406        }
407        lfs_unmount(&lfs) => 0;
408    }
409
410    lfs_mount(&lfs, &cfg) => 0;
411    lfs_dir_open(&lfs, &dir, "a") => 0;
412    lfs_dir_read(&lfs, &dir, &info) => 1;
413    assert(strcmp(info.name, ".") == 0);
414    assert(info.type == LFS_TYPE_DIR);
415    lfs_dir_read(&lfs, &dir, &info) => 1;
416    assert(strcmp(info.name, "..") == 0);
417    assert(info.type == LFS_TYPE_DIR);
418    lfs_dir_read(&lfs, &dir, &info) => 0;
419    lfs_dir_close(&lfs, &dir) => 0;
420    lfs_dir_open(&lfs, &dir, "d") => 0;
421    lfs_dir_read(&lfs, &dir, &info) => 1;
422    assert(strcmp(info.name, ".") == 0);
423    assert(info.type == LFS_TYPE_DIR);
424    lfs_dir_read(&lfs, &dir, &info) => 1;
425    assert(strcmp(info.name, "..") == 0);
426    assert(info.type == LFS_TYPE_DIR);
427    lfs_dir_read(&lfs, &dir, &info) => 1;
428    assert(strcmp(info.name, "hello") == 0);
429    assert(info.type == LFS_TYPE_REG);
430    assert(info.size == 5+8+6);
431    lfs_dir_read(&lfs, &dir, &info) => 0;
432    lfs_dir_close(&lfs, &dir) => 0;
433
434    lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
435    lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
436    lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
437    lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0;
438    lfs_file_read(&lfs, &file, buffer, 5) => 5;
439    memcmp(buffer, "hola\n", 5) => 0;
440    lfs_file_read(&lfs, &file, buffer, 8) => 8;
441    memcmp(buffer, "bonjour\n", 8) => 0;
442    lfs_file_read(&lfs, &file, buffer, 6) => 6;
443    memcmp(buffer, "ohayo\n", 6) => 0;
444    lfs_file_close(&lfs, &file) => 0;
445    lfs_unmount(&lfs) => 0;
446'''
447
448[[case]] # move dir
449code = '''
450    lfs_format(&lfs, &cfg) => 0;
451    lfs_mount(&lfs, &cfg) => 0;
452    lfs_mkdir(&lfs, "a") => 0;
453    lfs_mkdir(&lfs, "b") => 0;
454    lfs_mkdir(&lfs, "c") => 0;
455    lfs_mkdir(&lfs, "d") => 0;
456    lfs_mkdir(&lfs, "a/hi") => 0;
457    lfs_mkdir(&lfs, "a/hi/hola") => 0;
458    lfs_mkdir(&lfs, "a/hi/bonjour") => 0;
459    lfs_mkdir(&lfs, "a/hi/ohayo") => 0;
460    lfs_unmount(&lfs) => 0;
461
462    lfs_mount(&lfs, &cfg) => 0;
463    lfs_rename(&lfs, "a/hi", "c/hi") => 0;
464    lfs_unmount(&lfs) => 0;
465
466    lfs_mount(&lfs, &cfg) => 0;
467    lfs_dir_open(&lfs, &dir, "a") => 0;
468    lfs_dir_read(&lfs, &dir, &info) => 1;
469    assert(strcmp(info.name, ".") == 0);
470    assert(info.type == LFS_TYPE_DIR);
471    lfs_dir_read(&lfs, &dir, &info) => 1;
472    assert(strcmp(info.name, "..") == 0);
473    assert(info.type == LFS_TYPE_DIR);
474    lfs_dir_read(&lfs, &dir, &info) => 0;
475    lfs_dir_close(&lfs, &dir) => 0;
476    lfs_dir_open(&lfs, &dir, "c") => 0;
477    lfs_dir_read(&lfs, &dir, &info) => 1;
478    assert(strcmp(info.name, ".") == 0);
479    assert(info.type == LFS_TYPE_DIR);
480    lfs_dir_read(&lfs, &dir, &info) => 1;
481    assert(strcmp(info.name, "..") == 0);
482    assert(info.type == LFS_TYPE_DIR);
483    lfs_dir_read(&lfs, &dir, &info) => 1;
484    assert(strcmp(info.name, "hi") == 0);
485    assert(info.type == LFS_TYPE_DIR);
486    lfs_dir_read(&lfs, &dir, &info) => 0;
487    lfs_dir_close(&lfs, &dir) => 0;
488
489    lfs_dir_open(&lfs, &dir, "a/hi") => LFS_ERR_NOENT;
490    lfs_dir_open(&lfs, &dir, "b/hi") => LFS_ERR_NOENT;
491    lfs_dir_open(&lfs, &dir, "c/hi") => 0;
492    lfs_dir_read(&lfs, &dir, &info) => 1;
493    assert(strcmp(info.name, ".") == 0);
494    assert(info.type == LFS_TYPE_DIR);
495    lfs_dir_read(&lfs, &dir, &info) => 1;
496    assert(strcmp(info.name, "..") == 0);
497    assert(info.type == LFS_TYPE_DIR);
498    lfs_dir_read(&lfs, &dir, &info) => 1;
499    assert(strcmp(info.name, "bonjour") == 0);
500    assert(info.type == LFS_TYPE_DIR);
501    lfs_dir_read(&lfs, &dir, &info) => 1;
502    assert(strcmp(info.name, "hola") == 0);
503    assert(info.type == LFS_TYPE_DIR);
504    lfs_dir_read(&lfs, &dir, &info) => 1;
505    assert(strcmp(info.name, "ohayo") == 0);
506    assert(info.type == LFS_TYPE_DIR);
507    lfs_dir_read(&lfs, &dir, &info) => 0;
508    lfs_dir_close(&lfs, &dir) => 0;
509    lfs_dir_open(&lfs, &dir, "d/hi") => LFS_ERR_NOENT;
510    lfs_unmount(&lfs) => 0;
511'''
512
513[[case]] # move dir corrupt source
514in = "lfs.c"
515code = '''
516    lfs_format(&lfs, &cfg) => 0;
517    lfs_mount(&lfs, &cfg) => 0;
518    lfs_mkdir(&lfs, "a") => 0;
519    lfs_mkdir(&lfs, "b") => 0;
520    lfs_mkdir(&lfs, "c") => 0;
521    lfs_mkdir(&lfs, "d") => 0;
522    lfs_mkdir(&lfs, "a/hi") => 0;
523    lfs_mkdir(&lfs, "a/hi/hola") => 0;
524    lfs_mkdir(&lfs, "a/hi/bonjour") => 0;
525    lfs_mkdir(&lfs, "a/hi/ohayo") => 0;
526    lfs_unmount(&lfs) => 0;
527
528    lfs_mount(&lfs, &cfg) => 0;
529    lfs_rename(&lfs, "a/hi", "c/hi") => 0;
530    lfs_unmount(&lfs) => 0;
531
532    // corrupt the source
533    lfs_mount(&lfs, &cfg) => 0;
534    lfs_dir_open(&lfs, &dir, "a") => 0;
535    lfs_block_t block = dir.m.pair[0];
536    lfs_dir_close(&lfs, &dir) => 0;
537    lfs_unmount(&lfs) => 0;
538    uint8_t bbuffer[LFS_BLOCK_SIZE];
539    cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
540    int off = LFS_BLOCK_SIZE-1;
541    while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
542        off -= 1;
543    }
544    memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
545    cfg.erase(&cfg, block) => 0;
546    cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
547    cfg.sync(&cfg) => 0;
548
549    lfs_mount(&lfs, &cfg) => 0;
550    lfs_dir_open(&lfs, &dir, "a") => 0;
551    lfs_dir_read(&lfs, &dir, &info) => 1;
552    assert(strcmp(info.name, ".") == 0);
553    assert(info.type == LFS_TYPE_DIR);
554    lfs_dir_read(&lfs, &dir, &info) => 1;
555    assert(strcmp(info.name, "..") == 0);
556    assert(info.type == LFS_TYPE_DIR);
557    lfs_dir_read(&lfs, &dir, &info) => 0;
558    lfs_dir_close(&lfs, &dir) => 0;
559    lfs_dir_open(&lfs, &dir, "c") => 0;
560    lfs_dir_read(&lfs, &dir, &info) => 1;
561    assert(strcmp(info.name, ".") == 0);
562    assert(info.type == LFS_TYPE_DIR);
563    lfs_dir_read(&lfs, &dir, &info) => 1;
564    assert(strcmp(info.name, "..") == 0);
565    assert(info.type == LFS_TYPE_DIR);
566    lfs_dir_read(&lfs, &dir, &info) => 1;
567    assert(strcmp(info.name, "hi") == 0);
568    assert(info.type == LFS_TYPE_DIR);
569    lfs_dir_read(&lfs, &dir, &info) => 0;
570    lfs_dir_close(&lfs, &dir) => 0;
571
572    lfs_dir_open(&lfs, &dir, "a/hi") => LFS_ERR_NOENT;
573    lfs_dir_open(&lfs, &dir, "b/hi") => LFS_ERR_NOENT;
574    lfs_dir_open(&lfs, &dir, "c/hi") => 0;
575    lfs_dir_read(&lfs, &dir, &info) => 1;
576    assert(strcmp(info.name, ".") == 0);
577    assert(info.type == LFS_TYPE_DIR);
578    lfs_dir_read(&lfs, &dir, &info) => 1;
579    assert(strcmp(info.name, "..") == 0);
580    assert(info.type == LFS_TYPE_DIR);
581    lfs_dir_read(&lfs, &dir, &info) => 1;
582    assert(strcmp(info.name, "bonjour") == 0);
583    assert(info.type == LFS_TYPE_DIR);
584    lfs_dir_read(&lfs, &dir, &info) => 1;
585    assert(strcmp(info.name, "hola") == 0);
586    assert(info.type == LFS_TYPE_DIR);
587    lfs_dir_read(&lfs, &dir, &info) => 1;
588    assert(strcmp(info.name, "ohayo") == 0);
589    assert(info.type == LFS_TYPE_DIR);
590    lfs_dir_read(&lfs, &dir, &info) => 0;
591    lfs_dir_close(&lfs, &dir) => 0;
592    lfs_dir_open(&lfs, &dir, "d/hi") => LFS_ERR_NOENT;
593    lfs_unmount(&lfs) => 0;
594'''
595
596[[case]] # move dir corrupt source and dest
597in = "lfs.c"
598if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit
599code = '''
600    lfs_format(&lfs, &cfg) => 0;
601    lfs_mount(&lfs, &cfg) => 0;
602    lfs_mkdir(&lfs, "a") => 0;
603    lfs_mkdir(&lfs, "b") => 0;
604    lfs_mkdir(&lfs, "c") => 0;
605    lfs_mkdir(&lfs, "d") => 0;
606    lfs_mkdir(&lfs, "a/hi") => 0;
607    lfs_mkdir(&lfs, "a/hi/hola") => 0;
608    lfs_mkdir(&lfs, "a/hi/bonjour") => 0;
609    lfs_mkdir(&lfs, "a/hi/ohayo") => 0;
610    lfs_unmount(&lfs) => 0;
611
612    lfs_mount(&lfs, &cfg) => 0;
613    lfs_rename(&lfs, "a/hi", "c/hi") => 0;
614    lfs_unmount(&lfs) => 0;
615
616    // corrupt the source
617    lfs_mount(&lfs, &cfg) => 0;
618    lfs_dir_open(&lfs, &dir, "a") => 0;
619    lfs_block_t block = dir.m.pair[0];
620    lfs_dir_close(&lfs, &dir) => 0;
621    lfs_unmount(&lfs) => 0;
622    uint8_t bbuffer[LFS_BLOCK_SIZE];
623    cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
624    int off = LFS_BLOCK_SIZE-1;
625    while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
626        off -= 1;
627    }
628    memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
629    cfg.erase(&cfg, block) => 0;
630    cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
631    cfg.sync(&cfg) => 0;
632
633    // corrupt the destination
634    lfs_mount(&lfs, &cfg) => 0;
635    lfs_dir_open(&lfs, &dir, "c") => 0;
636    block = dir.m.pair[0];
637    lfs_dir_close(&lfs, &dir) => 0;
638    lfs_unmount(&lfs) => 0;
639    cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
640    off = LFS_BLOCK_SIZE-1;
641    while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
642        off -= 1;
643    }
644    memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
645    cfg.erase(&cfg, block) => 0;
646    cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
647    cfg.sync(&cfg) => 0;
648
649    lfs_mount(&lfs, &cfg) => 0;
650    lfs_dir_open(&lfs, &dir, "a") => 0;
651    lfs_dir_read(&lfs, &dir, &info) => 1;
652    assert(strcmp(info.name, ".") == 0);
653    assert(info.type == LFS_TYPE_DIR);
654    lfs_dir_read(&lfs, &dir, &info) => 1;
655    assert(strcmp(info.name, "..") == 0);
656    assert(info.type == LFS_TYPE_DIR);
657    lfs_dir_read(&lfs, &dir, &info) => 1;
658    assert(strcmp(info.name, "hi") == 0);
659    assert(info.type == LFS_TYPE_DIR);
660    lfs_dir_read(&lfs, &dir, &info) => 0;
661    lfs_dir_close(&lfs, &dir) => 0;
662    lfs_dir_open(&lfs, &dir, "c") => 0;
663    lfs_dir_read(&lfs, &dir, &info) => 1;
664    assert(strcmp(info.name, ".") == 0);
665    assert(info.type == LFS_TYPE_DIR);
666    lfs_dir_read(&lfs, &dir, &info) => 1;
667    assert(strcmp(info.name, "..") == 0);
668    assert(info.type == LFS_TYPE_DIR);
669    lfs_dir_read(&lfs, &dir, &info) => 0;
670    lfs_dir_close(&lfs, &dir) => 0;
671
672    lfs_dir_open(&lfs, &dir, "a/hi") => 0;
673    lfs_dir_read(&lfs, &dir, &info) => 1;
674    assert(strcmp(info.name, ".") == 0);
675    assert(info.type == LFS_TYPE_DIR);
676    lfs_dir_read(&lfs, &dir, &info) => 1;
677    assert(strcmp(info.name, "..") == 0);
678    assert(info.type == LFS_TYPE_DIR);
679    lfs_dir_read(&lfs, &dir, &info) => 1;
680    assert(strcmp(info.name, "bonjour") == 0);
681    assert(info.type == LFS_TYPE_DIR);
682    lfs_dir_read(&lfs, &dir, &info) => 1;
683    assert(strcmp(info.name, "hola") == 0);
684    assert(info.type == LFS_TYPE_DIR);
685    lfs_dir_read(&lfs, &dir, &info) => 1;
686    assert(strcmp(info.name, "ohayo") == 0);
687    assert(info.type == LFS_TYPE_DIR);
688    lfs_dir_read(&lfs, &dir, &info) => 0;
689    lfs_dir_close(&lfs, &dir) => 0;
690    lfs_dir_open(&lfs, &dir, "b/hi") => LFS_ERR_NOENT;
691    lfs_dir_open(&lfs, &dir, "c/hi") => LFS_ERR_NOENT;
692    lfs_dir_open(&lfs, &dir, "d/hi") => LFS_ERR_NOENT;
693    lfs_unmount(&lfs) => 0;
694'''
695
696[[case]] # move dir after corrupt
697in = "lfs.c"
698if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit
699code = '''
700    lfs_format(&lfs, &cfg) => 0;
701    lfs_mount(&lfs, &cfg) => 0;
702    lfs_mkdir(&lfs, "a") => 0;
703    lfs_mkdir(&lfs, "b") => 0;
704    lfs_mkdir(&lfs, "c") => 0;
705    lfs_mkdir(&lfs, "d") => 0;
706    lfs_mkdir(&lfs, "a/hi") => 0;
707    lfs_mkdir(&lfs, "a/hi/hola") => 0;
708    lfs_mkdir(&lfs, "a/hi/bonjour") => 0;
709    lfs_mkdir(&lfs, "a/hi/ohayo") => 0;
710    lfs_unmount(&lfs) => 0;
711
712    lfs_mount(&lfs, &cfg) => 0;
713    lfs_rename(&lfs, "a/hi", "c/hi") => 0;
714    lfs_unmount(&lfs) => 0;
715
716    // corrupt the source
717    lfs_mount(&lfs, &cfg) => 0;
718    lfs_dir_open(&lfs, &dir, "a") => 0;
719    lfs_block_t block = dir.m.pair[0];
720    lfs_dir_close(&lfs, &dir) => 0;
721    lfs_unmount(&lfs) => 0;
722    uint8_t bbuffer[LFS_BLOCK_SIZE];
723    cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
724    int off = LFS_BLOCK_SIZE-1;
725    while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
726        off -= 1;
727    }
728    memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
729    cfg.erase(&cfg, block) => 0;
730    cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
731    cfg.sync(&cfg) => 0;
732
733    // corrupt the destination
734    lfs_mount(&lfs, &cfg) => 0;
735    lfs_dir_open(&lfs, &dir, "c") => 0;
736    block = dir.m.pair[0];
737    lfs_dir_close(&lfs, &dir) => 0;
738    lfs_unmount(&lfs) => 0;
739    cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
740    off = LFS_BLOCK_SIZE-1;
741    while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
742        off -= 1;
743    }
744    memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
745    cfg.erase(&cfg, block) => 0;
746    cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
747    cfg.sync(&cfg) => 0;
748
749    // continue move
750    lfs_mount(&lfs, &cfg) => 0;
751    lfs_rename(&lfs, "a/hi", "c/hi") => 0;
752    lfs_unmount(&lfs) => 0;
753
754    lfs_mount(&lfs, &cfg) => 0;
755    lfs_dir_open(&lfs, &dir, "a") => 0;
756    lfs_dir_read(&lfs, &dir, &info) => 1;
757    assert(strcmp(info.name, ".") == 0);
758    assert(info.type == LFS_TYPE_DIR);
759    lfs_dir_read(&lfs, &dir, &info) => 1;
760    assert(strcmp(info.name, "..") == 0);
761    assert(info.type == LFS_TYPE_DIR);
762    lfs_dir_read(&lfs, &dir, &info) => 0;
763    lfs_dir_close(&lfs, &dir) => 0;
764    lfs_dir_open(&lfs, &dir, "c") => 0;
765    lfs_dir_read(&lfs, &dir, &info) => 1;
766    assert(strcmp(info.name, ".") == 0);
767    assert(info.type == LFS_TYPE_DIR);
768    lfs_dir_read(&lfs, &dir, &info) => 1;
769    assert(strcmp(info.name, "..") == 0);
770    assert(info.type == LFS_TYPE_DIR);
771    lfs_dir_read(&lfs, &dir, &info) => 1;
772    assert(strcmp(info.name, "hi") == 0);
773    assert(info.type == LFS_TYPE_DIR);
774    lfs_dir_read(&lfs, &dir, &info) => 0;
775    lfs_dir_close(&lfs, &dir) => 0;
776
777    lfs_dir_open(&lfs, &dir, "a/hi") => LFS_ERR_NOENT;
778    lfs_dir_open(&lfs, &dir, "b/hi") => LFS_ERR_NOENT;
779    lfs_dir_open(&lfs, &dir, "c/hi") => 0;
780    lfs_dir_read(&lfs, &dir, &info) => 1;
781    assert(strcmp(info.name, ".") == 0);
782    assert(info.type == LFS_TYPE_DIR);
783    lfs_dir_read(&lfs, &dir, &info) => 1;
784    assert(strcmp(info.name, "..") == 0);
785    assert(info.type == LFS_TYPE_DIR);
786    lfs_dir_read(&lfs, &dir, &info) => 1;
787    assert(strcmp(info.name, "bonjour") == 0);
788    assert(info.type == LFS_TYPE_DIR);
789    lfs_dir_read(&lfs, &dir, &info) => 1;
790    assert(strcmp(info.name, "hola") == 0);
791    assert(info.type == LFS_TYPE_DIR);
792    lfs_dir_read(&lfs, &dir, &info) => 1;
793    assert(strcmp(info.name, "ohayo") == 0);
794    assert(info.type == LFS_TYPE_DIR);
795    lfs_dir_read(&lfs, &dir, &info) => 0;
796    lfs_dir_close(&lfs, &dir) => 0;
797    lfs_dir_open(&lfs, &dir, "d/hi") => LFS_ERR_NOENT;
798    lfs_unmount(&lfs) => 0;
799'''
800
801[[case]] # simple reentrant move dir
802reentrant = true
803code = '''
804    err = lfs_mount(&lfs, &cfg);
805    if (err) {
806        lfs_format(&lfs, &cfg) => 0;
807        lfs_mount(&lfs, &cfg) => 0;
808    }
809    err = lfs_mkdir(&lfs, "a");
810    assert(!err || err == LFS_ERR_EXIST);
811    err = lfs_mkdir(&lfs, "b");
812    assert(!err || err == LFS_ERR_EXIST);
813    err = lfs_mkdir(&lfs, "c");
814    assert(!err || err == LFS_ERR_EXIST);
815    err = lfs_mkdir(&lfs, "d");
816    assert(!err || err == LFS_ERR_EXIST);
817    lfs_unmount(&lfs) => 0;
818
819    while (true) {
820        lfs_mount(&lfs, &cfg) => 0;
821        // there should never exist _2_ hi directories
822        int count = 0;
823        if (lfs_stat(&lfs, "a/hi", &info) == 0) {
824            assert(strcmp(info.name, "hi") == 0);
825            assert(info.type == LFS_TYPE_DIR);
826            count += 1;
827        }
828        if (lfs_stat(&lfs, "b/hi", &info) == 0) {
829            assert(strcmp(info.name, "hi") == 0);
830            assert(info.type == LFS_TYPE_DIR);
831            count += 1;
832        }
833        if (lfs_stat(&lfs, "c/hi", &info) == 0) {
834            assert(strcmp(info.name, "hi") == 0);
835            assert(info.type == LFS_TYPE_DIR);
836            count += 1;
837        }
838        if (lfs_stat(&lfs, "d/hi", &info) == 0) {
839            assert(strcmp(info.name, "hi") == 0);
840            assert(info.type == LFS_TYPE_DIR);
841            count += 1;
842        }
843        assert(count <= 1);
844        lfs_unmount(&lfs) => 0;
845
846        lfs_mount(&lfs, &cfg) => 0;
847        if (lfs_stat(&lfs, "a/hi", &info) == 0) {
848            lfs_rename(&lfs, "a/hi", "b/hi") => 0;
849        } else if (lfs_stat(&lfs, "b/hi", &info) == 0) {
850            lfs_rename(&lfs, "b/hi", "c/hi") => 0;
851        } else if (lfs_stat(&lfs, "c/hi", &info) == 0) {
852            lfs_rename(&lfs, "c/hi", "d/hi") => 0;
853        } else if (lfs_stat(&lfs, "d/hi", &info) == 0) {
854            lfs_unmount(&lfs) => 0;
855            break; // success
856        } else {
857            // create dir and rename for atomicity
858            err = lfs_mkdir(&lfs, "temp");
859            assert(!err || err == LFS_ERR_EXIST);
860            err = lfs_mkdir(&lfs, "temp/hola");
861            assert(!err || err == LFS_ERR_EXIST);
862            err = lfs_mkdir(&lfs, "temp/bonjour");
863            assert(!err || err == LFS_ERR_EXIST);
864            err = lfs_mkdir(&lfs, "temp/ohayo");
865            assert(!err || err == LFS_ERR_EXIST);
866            lfs_rename(&lfs, "temp", "a/hi") => 0;
867        }
868        lfs_unmount(&lfs) => 0;
869    }
870
871    lfs_mount(&lfs, &cfg) => 0;
872    lfs_dir_open(&lfs, &dir, "a") => 0;
873    lfs_dir_read(&lfs, &dir, &info) => 1;
874    assert(strcmp(info.name, ".") == 0);
875    assert(info.type == LFS_TYPE_DIR);
876    lfs_dir_read(&lfs, &dir, &info) => 1;
877    assert(strcmp(info.name, "..") == 0);
878    assert(info.type == LFS_TYPE_DIR);
879    lfs_dir_read(&lfs, &dir, &info) => 0;
880    lfs_dir_close(&lfs, &dir) => 0;
881    lfs_dir_open(&lfs, &dir, "d") => 0;
882    lfs_dir_read(&lfs, &dir, &info) => 1;
883    assert(strcmp(info.name, ".") == 0);
884    assert(info.type == LFS_TYPE_DIR);
885    lfs_dir_read(&lfs, &dir, &info) => 1;
886    assert(strcmp(info.name, "..") == 0);
887    assert(info.type == LFS_TYPE_DIR);
888    lfs_dir_read(&lfs, &dir, &info) => 1;
889    assert(strcmp(info.name, "hi") == 0);
890    assert(info.type == LFS_TYPE_DIR);
891    lfs_dir_read(&lfs, &dir, &info) => 0;
892    lfs_dir_close(&lfs, &dir) => 0;
893
894    lfs_dir_open(&lfs, &dir, "a/hi") => LFS_ERR_NOENT;
895    lfs_dir_open(&lfs, &dir, "b/hi") => LFS_ERR_NOENT;
896    lfs_dir_open(&lfs, &dir, "c/hi") => LFS_ERR_NOENT;
897    lfs_dir_open(&lfs, &dir, "d/hi") => 0;
898    lfs_dir_read(&lfs, &dir, &info) => 1;
899    assert(strcmp(info.name, ".") == 0);
900    assert(info.type == LFS_TYPE_DIR);
901    lfs_dir_read(&lfs, &dir, &info) => 1;
902    assert(strcmp(info.name, "..") == 0);
903    assert(info.type == LFS_TYPE_DIR);
904    lfs_dir_read(&lfs, &dir, &info) => 1;
905    assert(strcmp(info.name, "bonjour") == 0);
906    assert(info.type == LFS_TYPE_DIR);
907    lfs_dir_read(&lfs, &dir, &info) => 1;
908    assert(strcmp(info.name, "hola") == 0);
909    assert(info.type == LFS_TYPE_DIR);
910    lfs_dir_read(&lfs, &dir, &info) => 1;
911    assert(strcmp(info.name, "ohayo") == 0);
912    assert(info.type == LFS_TYPE_DIR);
913    lfs_dir_read(&lfs, &dir, &info) => 0;
914    lfs_dir_close(&lfs, &dir) => 0;
915    lfs_unmount(&lfs) => 0;
916'''
917
918[[case]] # move state stealing
919code = '''
920    lfs_format(&lfs, &cfg) => 0;
921    lfs_mount(&lfs, &cfg) => 0;
922    lfs_mkdir(&lfs, "a") => 0;
923    lfs_mkdir(&lfs, "b") => 0;
924    lfs_mkdir(&lfs, "c") => 0;
925    lfs_mkdir(&lfs, "d") => 0;
926    lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0;
927    lfs_file_write(&lfs, &file, "hola\n", 5) => 5;
928    lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8;
929    lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6;
930    lfs_file_close(&lfs, &file) => 0;
931    lfs_unmount(&lfs) => 0;
932
933    lfs_mount(&lfs, &cfg) => 0;
934    lfs_rename(&lfs, "a/hello", "b/hello") => 0;
935    lfs_unmount(&lfs) => 0;
936    lfs_mount(&lfs, &cfg) => 0;
937    lfs_rename(&lfs, "b/hello", "c/hello") => 0;
938    lfs_unmount(&lfs) => 0;
939    lfs_mount(&lfs, &cfg) => 0;
940    lfs_rename(&lfs, "c/hello", "d/hello") => 0;
941    lfs_unmount(&lfs) => 0;
942
943    lfs_mount(&lfs, &cfg) => 0;
944    lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
945    lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
946    lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
947    lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0;
948    lfs_file_read(&lfs, &file, buffer, 5) => 5;
949    memcmp(buffer, "hola\n", 5) => 0;
950    lfs_file_read(&lfs, &file, buffer, 8) => 8;
951    memcmp(buffer, "bonjour\n", 8) => 0;
952    lfs_file_read(&lfs, &file, buffer, 6) => 6;
953    memcmp(buffer, "ohayo\n", 6) => 0;
954    lfs_file_close(&lfs, &file) => 0;
955    lfs_unmount(&lfs) => 0;
956
957    lfs_mount(&lfs, &cfg) => 0;
958    lfs_remove(&lfs, "b") => 0;
959    lfs_remove(&lfs, "c") => 0;
960    lfs_unmount(&lfs) => 0;
961
962    lfs_mount(&lfs, &cfg) => 0;
963    lfs_stat(&lfs, "a", &info) => 0;
964    lfs_stat(&lfs, "b", &info) => LFS_ERR_NOENT;
965    lfs_stat(&lfs, "c", &info) => LFS_ERR_NOENT;
966    lfs_stat(&lfs, "d", &info) => 0;
967    lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
968    lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
969    lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
970    lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0;
971    lfs_file_read(&lfs, &file, buffer, 5) => 5;
972    memcmp(buffer, "hola\n", 5) => 0;
973    lfs_file_read(&lfs, &file, buffer, 8) => 8;
974    memcmp(buffer, "bonjour\n", 8) => 0;
975    lfs_file_read(&lfs, &file, buffer, 6) => 6;
976    memcmp(buffer, "ohayo\n", 6) => 0;
977    lfs_file_close(&lfs, &file) => 0;
978    lfs_unmount(&lfs) => 0;
979'''
980
981# Other specific corner cases
982[[case]] # create + delete in same commit with neighbors
983code = '''
984    lfs_format(&lfs, &cfg) => 0;
985    lfs_mount(&lfs, &cfg) => 0;
986
987    // littlefs keeps files sorted, so we know the order these will be in
988    lfs_file_open(&lfs, &file, "/1.move_me",
989            LFS_O_WRONLY | LFS_O_CREAT) => 0;
990    lfs_file_close(&lfs, &file) => 0;
991
992    lfs_file_open(&lfs, &file, "/0.before",
993            LFS_O_WRONLY | LFS_O_CREAT) => 0;
994    lfs_file_write(&lfs, &file, "test.1", 7) => 7;
995    lfs_file_close(&lfs, &file) => 0;
996
997    lfs_file_open(&lfs, &file, "/2.in_between",
998            LFS_O_WRONLY | LFS_O_CREAT) => 0;
999    lfs_file_write(&lfs, &file, "test.2", 7) => 7;
1000    lfs_file_close(&lfs, &file) => 0;
1001
1002    lfs_file_open(&lfs, &file, "/4.after",
1003            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1004    lfs_file_write(&lfs, &file, "test.3", 7) => 7;
1005    lfs_file_close(&lfs, &file) => 0;
1006
1007    lfs_file_t files[3];
1008    lfs_file_open(&lfs, &files[0], "0.before",
1009            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1010    lfs_file_open(&lfs, &files[1], "2.in_between",
1011            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1012    lfs_file_open(&lfs, &files[2], "4.after",
1013            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1014    lfs_file_write(&lfs, &files[0], "test.4", 7) => 7;
1015    lfs_file_write(&lfs, &files[1], "test.5", 7) => 7;
1016    lfs_file_write(&lfs, &files[2], "test.6", 7) => 7;
1017
1018    // rename file while everything is open, this triggers both
1019    // a create and delete simultaneously
1020    lfs_rename(&lfs, "/1.move_me", "/3.move_me") => 0;
1021
1022    lfs_file_close(&lfs, &files[0]) => 0;
1023    lfs_file_close(&lfs, &files[1]) => 0;
1024    lfs_file_close(&lfs, &files[2]) => 0;
1025
1026    // check that nothing was corrupted
1027    lfs_dir_open(&lfs, &dir, "/") => 0;
1028    lfs_dir_read(&lfs, &dir, &info) => 1;
1029    assert(strcmp(info.name, ".") == 0);
1030    assert(info.type == LFS_TYPE_DIR);
1031    lfs_dir_read(&lfs, &dir, &info) => 1;
1032    assert(strcmp(info.name, "..") == 0);
1033    assert(info.type == LFS_TYPE_DIR);
1034    lfs_dir_read(&lfs, &dir, &info) => 1;
1035    assert(strcmp(info.name, "0.before") == 0);
1036    assert(info.type == LFS_TYPE_REG);
1037    assert(info.size == 7);
1038    lfs_dir_read(&lfs, &dir, &info) => 1;
1039    assert(strcmp(info.name, "2.in_between") == 0);
1040    assert(info.type == LFS_TYPE_REG);
1041    assert(info.size == 7);
1042    lfs_dir_read(&lfs, &dir, &info) => 1;
1043    assert(strcmp(info.name, "3.move_me") == 0);
1044    assert(info.type == LFS_TYPE_REG);
1045    assert(info.size == 0);
1046    lfs_dir_read(&lfs, &dir, &info) => 1;
1047    assert(strcmp(info.name, "4.after") == 0);
1048    assert(info.type == LFS_TYPE_REG);
1049    assert(info.size == 7);
1050    lfs_dir_read(&lfs, &dir, &info) => 0;
1051    lfs_dir_close(&lfs, &dir) => 0;
1052
1053    lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0;
1054    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1055    assert(strcmp((char*)buffer, "test.4") == 0);
1056    lfs_file_close(&lfs, &file) => 0;
1057    lfs_file_open(&lfs, &file, "/2.in_between", LFS_O_RDONLY) => 0;
1058    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1059    assert(strcmp((char*)buffer, "test.5") == 0);
1060    lfs_file_close(&lfs, &file) => 0;
1061    lfs_file_open(&lfs, &file, "/4.after", LFS_O_RDONLY) => 0;
1062    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1063    assert(strcmp((char*)buffer, "test.6") == 0);
1064    lfs_file_close(&lfs, &file) => 0;
1065
1066    // now move back
1067    lfs_file_open(&lfs, &files[0], "0.before",
1068            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1069    lfs_file_open(&lfs, &files[1], "2.in_between",
1070            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1071    lfs_file_open(&lfs, &files[2], "4.after",
1072            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1073    lfs_file_write(&lfs, &files[0], "test.7", 7) => 7;
1074    lfs_file_write(&lfs, &files[1], "test.8", 7) => 7;
1075    lfs_file_write(&lfs, &files[2], "test.9", 7) => 7;
1076
1077    // rename file while everything is open, this triggers both
1078    // a create and delete simultaneously
1079    lfs_rename(&lfs, "/3.move_me", "/1.move_me") => 0;
1080
1081    lfs_file_close(&lfs, &files[0]) => 0;
1082    lfs_file_close(&lfs, &files[1]) => 0;
1083    lfs_file_close(&lfs, &files[2]) => 0;
1084
1085    // and check that nothing was corrupted again
1086    lfs_dir_open(&lfs, &dir, "/") => 0;
1087    lfs_dir_read(&lfs, &dir, &info) => 1;
1088    assert(strcmp(info.name, ".") == 0);
1089    assert(info.type == LFS_TYPE_DIR);
1090    lfs_dir_read(&lfs, &dir, &info) => 1;
1091    assert(strcmp(info.name, "..") == 0);
1092    assert(info.type == LFS_TYPE_DIR);
1093    lfs_dir_read(&lfs, &dir, &info) => 1;
1094    assert(strcmp(info.name, "0.before") == 0);
1095    assert(info.type == LFS_TYPE_REG);
1096    assert(info.size == 7);
1097    lfs_dir_read(&lfs, &dir, &info) => 1;
1098    assert(strcmp(info.name, "1.move_me") == 0);
1099    assert(info.type == LFS_TYPE_REG);
1100    assert(info.size == 0);
1101    lfs_dir_read(&lfs, &dir, &info) => 1;
1102    assert(strcmp(info.name, "2.in_between") == 0);
1103    assert(info.type == LFS_TYPE_REG);
1104    assert(info.size == 7);
1105    lfs_dir_read(&lfs, &dir, &info) => 1;
1106    assert(strcmp(info.name, "4.after") == 0);
1107    assert(info.type == LFS_TYPE_REG);
1108    assert(info.size == 7);
1109    lfs_dir_read(&lfs, &dir, &info) => 0;
1110    lfs_dir_close(&lfs, &dir) => 0;
1111
1112    lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0;
1113    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1114    assert(strcmp((char*)buffer, "test.7") == 0);
1115    lfs_file_close(&lfs, &file) => 0;
1116    lfs_file_open(&lfs, &file, "/2.in_between", LFS_O_RDONLY) => 0;
1117    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1118    assert(strcmp((char*)buffer, "test.8") == 0);
1119    lfs_file_close(&lfs, &file) => 0;
1120    lfs_file_open(&lfs, &file, "/4.after", LFS_O_RDONLY) => 0;
1121    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1122    assert(strcmp((char*)buffer, "test.9") == 0);
1123    lfs_file_close(&lfs, &file) => 0;
1124    lfs_unmount(&lfs) => 0;
1125'''
1126
1127# Other specific corner cases
1128[[case]] # create + delete + delete in same commit with neighbors
1129code = '''
1130    lfs_format(&lfs, &cfg) => 0;
1131    lfs_mount(&lfs, &cfg) => 0;
1132
1133    // littlefs keeps files sorted, so we know the order these will be in
1134    lfs_file_open(&lfs, &file, "/1.move_me",
1135            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1136    lfs_file_close(&lfs, &file) => 0;
1137    lfs_file_open(&lfs, &file, "/3.move_me",
1138            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1139    lfs_file_write(&lfs, &file, "remove me",
1140            sizeof("remove me")) => sizeof("remove me");
1141    lfs_file_close(&lfs, &file) => 0;
1142
1143    lfs_file_open(&lfs, &file, "/0.before",
1144            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1145    lfs_file_write(&lfs, &file, "test.1", 7) => 7;
1146    lfs_file_close(&lfs, &file) => 0;
1147
1148    lfs_file_open(&lfs, &file, "/2.in_between",
1149            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1150    lfs_file_write(&lfs, &file, "test.2", 7) => 7;
1151    lfs_file_close(&lfs, &file) => 0;
1152
1153    lfs_file_open(&lfs, &file, "/4.after",
1154            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1155    lfs_file_write(&lfs, &file, "test.3", 7) => 7;
1156    lfs_file_close(&lfs, &file) => 0;
1157
1158    lfs_file_t files[3];
1159    lfs_file_open(&lfs, &files[0], "0.before",
1160            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1161    lfs_file_open(&lfs, &files[1], "2.in_between",
1162            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1163    lfs_file_open(&lfs, &files[2], "4.after",
1164            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1165    lfs_file_write(&lfs, &files[0], "test.4", 7) => 7;
1166    lfs_file_write(&lfs, &files[1], "test.5", 7) => 7;
1167    lfs_file_write(&lfs, &files[2], "test.6", 7) => 7;
1168
1169    // rename file while everything is open, this triggers both
1170    // a create and delete simultaneously
1171    lfs_rename(&lfs, "/1.move_me", "/3.move_me") => 0;
1172
1173    lfs_file_close(&lfs, &files[0]) => 0;
1174    lfs_file_close(&lfs, &files[1]) => 0;
1175    lfs_file_close(&lfs, &files[2]) => 0;
1176
1177    // check that nothing was corrupted
1178    lfs_dir_open(&lfs, &dir, "/") => 0;
1179    lfs_dir_read(&lfs, &dir, &info) => 1;
1180    assert(strcmp(info.name, ".") == 0);
1181    assert(info.type == LFS_TYPE_DIR);
1182    lfs_dir_read(&lfs, &dir, &info) => 1;
1183    assert(strcmp(info.name, "..") == 0);
1184    assert(info.type == LFS_TYPE_DIR);
1185    lfs_dir_read(&lfs, &dir, &info) => 1;
1186    assert(strcmp(info.name, "0.before") == 0);
1187    assert(info.type == LFS_TYPE_REG);
1188    assert(info.size == 7);
1189    lfs_dir_read(&lfs, &dir, &info) => 1;
1190    assert(strcmp(info.name, "2.in_between") == 0);
1191    assert(info.type == LFS_TYPE_REG);
1192    assert(info.size == 7);
1193    lfs_dir_read(&lfs, &dir, &info) => 1;
1194    assert(strcmp(info.name, "3.move_me") == 0);
1195    assert(info.type == LFS_TYPE_REG);
1196    assert(info.size == 0);
1197    lfs_dir_read(&lfs, &dir, &info) => 1;
1198    assert(strcmp(info.name, "4.after") == 0);
1199    assert(info.type == LFS_TYPE_REG);
1200    assert(info.size == 7);
1201    lfs_dir_read(&lfs, &dir, &info) => 0;
1202    lfs_dir_close(&lfs, &dir) => 0;
1203
1204    lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0;
1205    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1206    assert(strcmp((char*)buffer, "test.4") == 0);
1207    lfs_file_close(&lfs, &file) => 0;
1208    lfs_file_open(&lfs, &file, "/2.in_between", LFS_O_RDONLY) => 0;
1209    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1210    assert(strcmp((char*)buffer, "test.5") == 0);
1211    lfs_file_close(&lfs, &file) => 0;
1212    lfs_file_open(&lfs, &file, "/4.after", LFS_O_RDONLY) => 0;
1213    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1214    assert(strcmp((char*)buffer, "test.6") == 0);
1215    lfs_file_close(&lfs, &file) => 0;
1216
1217    // now move back
1218    lfs_file_open(&lfs, &file, "/1.move_me",
1219            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1220    lfs_file_write(&lfs, &file, "remove me",
1221            sizeof("remove me")) => sizeof("remove me");
1222    lfs_file_close(&lfs, &file) => 0;
1223
1224    lfs_file_open(&lfs, &files[0], "0.before",
1225            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1226    lfs_file_open(&lfs, &files[1], "2.in_between",
1227            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1228    lfs_file_open(&lfs, &files[2], "4.after",
1229            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1230    lfs_file_write(&lfs, &files[0], "test.7", 7) => 7;
1231    lfs_file_write(&lfs, &files[1], "test.8", 7) => 7;
1232    lfs_file_write(&lfs, &files[2], "test.9", 7) => 7;
1233
1234    // rename file while everything is open, this triggers both
1235    // a create and delete simultaneously
1236    lfs_rename(&lfs, "/3.move_me", "/1.move_me") => 0;
1237
1238    lfs_file_close(&lfs, &files[0]) => 0;
1239    lfs_file_close(&lfs, &files[1]) => 0;
1240    lfs_file_close(&lfs, &files[2]) => 0;
1241
1242    // and check that nothing was corrupted again
1243    lfs_dir_open(&lfs, &dir, "/") => 0;
1244    lfs_dir_read(&lfs, &dir, &info) => 1;
1245    assert(strcmp(info.name, ".") == 0);
1246    assert(info.type == LFS_TYPE_DIR);
1247    lfs_dir_read(&lfs, &dir, &info) => 1;
1248    assert(strcmp(info.name, "..") == 0);
1249    assert(info.type == LFS_TYPE_DIR);
1250    lfs_dir_read(&lfs, &dir, &info) => 1;
1251    assert(strcmp(info.name, "0.before") == 0);
1252    assert(info.type == LFS_TYPE_REG);
1253    assert(info.size == 7);
1254    lfs_dir_read(&lfs, &dir, &info) => 1;
1255    assert(strcmp(info.name, "1.move_me") == 0);
1256    assert(info.type == LFS_TYPE_REG);
1257    assert(info.size == 0);
1258    lfs_dir_read(&lfs, &dir, &info) => 1;
1259    assert(strcmp(info.name, "2.in_between") == 0);
1260    assert(info.type == LFS_TYPE_REG);
1261    assert(info.size == 7);
1262    lfs_dir_read(&lfs, &dir, &info) => 1;
1263    assert(strcmp(info.name, "4.after") == 0);
1264    assert(info.type == LFS_TYPE_REG);
1265    assert(info.size == 7);
1266    lfs_dir_read(&lfs, &dir, &info) => 0;
1267    lfs_dir_close(&lfs, &dir) => 0;
1268
1269    lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0;
1270    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1271    assert(strcmp((char*)buffer, "test.7") == 0);
1272    lfs_file_close(&lfs, &file) => 0;
1273    lfs_file_open(&lfs, &file, "/2.in_between", LFS_O_RDONLY) => 0;
1274    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1275    assert(strcmp((char*)buffer, "test.8") == 0);
1276    lfs_file_close(&lfs, &file) => 0;
1277    lfs_file_open(&lfs, &file, "/4.after", LFS_O_RDONLY) => 0;
1278    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1279    assert(strcmp((char*)buffer, "test.9") == 0);
1280    lfs_file_close(&lfs, &file) => 0;
1281    lfs_unmount(&lfs) => 0;
1282'''
1283
1284[[case]] # create + delete in different dirs with neighbors
1285code = '''
1286    lfs_format(&lfs, &cfg) => 0;
1287    lfs_mount(&lfs, &cfg) => 0;
1288
1289    // littlefs keeps files sorted, so we know the order these will be in
1290    lfs_mkdir(&lfs, "/dir.1") => 0;
1291    lfs_mkdir(&lfs, "/dir.2") => 0;
1292    lfs_file_open(&lfs, &file, "/dir.1/1.move_me",
1293            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1294    lfs_file_close(&lfs, &file) => 0;
1295    lfs_file_open(&lfs, &file, "/dir.2/1.move_me",
1296            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1297    lfs_file_write(&lfs, &file, "remove me",
1298            sizeof("remove me")) => sizeof("remove me");
1299    lfs_file_close(&lfs, &file) => 0;
1300
1301    lfs_file_open(&lfs, &file, "/dir.1/0.before",
1302            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1303    lfs_file_write(&lfs, &file, "test.1", 7) => 7;
1304    lfs_file_close(&lfs, &file) => 0;
1305    lfs_file_open(&lfs, &file, "/dir.1/2.after",
1306            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1307    lfs_file_write(&lfs, &file, "test.2", 7) => 7;
1308    lfs_file_close(&lfs, &file) => 0;
1309
1310    lfs_file_open(&lfs, &file, "/dir.2/0.before",
1311            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1312    lfs_file_write(&lfs, &file, "test.3", 7) => 7;
1313    lfs_file_close(&lfs, &file) => 0;
1314    lfs_file_open(&lfs, &file, "/dir.2/2.after",
1315            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1316    lfs_file_write(&lfs, &file, "test.4", 7) => 7;
1317    lfs_file_close(&lfs, &file) => 0;
1318
1319    lfs_file_t files[4];
1320    lfs_file_open(&lfs, &files[0], "/dir.1/0.before",
1321            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1322    lfs_file_open(&lfs, &files[1], "/dir.1/2.after",
1323            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1324    lfs_file_open(&lfs, &files[2], "/dir.2/0.before",
1325            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1326    lfs_file_open(&lfs, &files[3], "/dir.2/2.after",
1327            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1328    lfs_file_write(&lfs, &files[0], "test.5", 7) => 7;
1329    lfs_file_write(&lfs, &files[1], "test.6", 7) => 7;
1330    lfs_file_write(&lfs, &files[2], "test.7", 7) => 7;
1331    lfs_file_write(&lfs, &files[3], "test.8", 7) => 7;
1332
1333    // rename file while everything is open, this triggers both
1334    // a create and delete as it overwrites the destination file
1335    lfs_rename(&lfs, "/dir.1/1.move_me", "/dir.2/1.move_me") => 0;
1336
1337    lfs_file_close(&lfs, &files[0]) => 0;
1338    lfs_file_close(&lfs, &files[1]) => 0;
1339    lfs_file_close(&lfs, &files[2]) => 0;
1340    lfs_file_close(&lfs, &files[3]) => 0;
1341
1342    // check that nothing was corrupted
1343    lfs_dir_open(&lfs, &dir, "/") => 0;
1344    lfs_dir_read(&lfs, &dir, &info) => 1;
1345    assert(strcmp(info.name, ".") == 0);
1346    assert(info.type == LFS_TYPE_DIR);
1347    lfs_dir_read(&lfs, &dir, &info) => 1;
1348    assert(strcmp(info.name, "..") == 0);
1349    assert(info.type == LFS_TYPE_DIR);
1350    lfs_dir_read(&lfs, &dir, &info) => 1;
1351    assert(strcmp(info.name, "dir.1") == 0);
1352    assert(info.type == LFS_TYPE_DIR);
1353    lfs_dir_read(&lfs, &dir, &info) => 1;
1354    assert(strcmp(info.name, "dir.2") == 0);
1355    assert(info.type == LFS_TYPE_DIR);
1356    lfs_dir_read(&lfs, &dir, &info) => 0;
1357    lfs_dir_close(&lfs, &dir) => 0;
1358
1359    lfs_dir_open(&lfs, &dir, "/dir.1") => 0;
1360    lfs_dir_read(&lfs, &dir, &info) => 1;
1361    assert(strcmp(info.name, ".") == 0);
1362    assert(info.type == LFS_TYPE_DIR);
1363    lfs_dir_read(&lfs, &dir, &info) => 1;
1364    assert(strcmp(info.name, "..") == 0);
1365    assert(info.type == LFS_TYPE_DIR);
1366    lfs_dir_read(&lfs, &dir, &info) => 1;
1367    assert(strcmp(info.name, "0.before") == 0);
1368    assert(info.type == LFS_TYPE_REG);
1369    assert(info.size == 7);
1370    lfs_dir_read(&lfs, &dir, &info) => 1;
1371    assert(strcmp(info.name, "2.after") == 0);
1372    assert(info.type == LFS_TYPE_REG);
1373    assert(info.size == 7);
1374    lfs_dir_read(&lfs, &dir, &info) => 0;
1375    lfs_dir_close(&lfs, &dir) => 0;
1376
1377    lfs_dir_open(&lfs, &dir, "/dir.2") => 0;
1378    lfs_dir_read(&lfs, &dir, &info) => 1;
1379    assert(strcmp(info.name, ".") == 0);
1380    assert(info.type == LFS_TYPE_DIR);
1381    lfs_dir_read(&lfs, &dir, &info) => 1;
1382    assert(strcmp(info.name, "..") == 0);
1383    assert(info.type == LFS_TYPE_DIR);
1384    lfs_dir_read(&lfs, &dir, &info) => 1;
1385    assert(strcmp(info.name, "0.before") == 0);
1386    assert(info.type == LFS_TYPE_REG);
1387    assert(info.size == 7);
1388    lfs_dir_read(&lfs, &dir, &info) => 1;
1389    assert(strcmp(info.name, "1.move_me") == 0);
1390    assert(info.type == LFS_TYPE_REG);
1391    assert(info.size == 0);
1392    lfs_dir_read(&lfs, &dir, &info) => 1;
1393    assert(strcmp(info.name, "2.after") == 0);
1394    assert(info.type == LFS_TYPE_REG);
1395    assert(info.size == 7);
1396    lfs_dir_read(&lfs, &dir, &info) => 0;
1397    lfs_dir_close(&lfs, &dir) => 0;
1398
1399    lfs_file_open(&lfs, &file, "/dir.1/0.before", LFS_O_RDONLY) => 0;
1400    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1401    assert(strcmp((char*)buffer, "test.5") == 0);
1402    lfs_file_close(&lfs, &file) => 0;
1403    lfs_file_open(&lfs, &file, "/dir.1/2.after", LFS_O_RDONLY) => 0;
1404    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1405    assert(strcmp((char*)buffer, "test.6") == 0);
1406    lfs_file_close(&lfs, &file) => 0;
1407    lfs_file_open(&lfs, &file, "/dir.2/0.before", LFS_O_RDONLY) => 0;
1408    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1409    assert(strcmp((char*)buffer, "test.7") == 0);
1410    lfs_file_close(&lfs, &file) => 0;
1411    lfs_file_open(&lfs, &file, "/dir.2/2.after", LFS_O_RDONLY) => 0;
1412    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1413    assert(strcmp((char*)buffer, "test.8") == 0);
1414    lfs_file_close(&lfs, &file) => 0;
1415
1416    // now move back
1417    lfs_file_open(&lfs, &file, "/dir.1/1.move_me",
1418            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1419    lfs_file_write(&lfs, &file, "remove me",
1420            sizeof("remove me")) => sizeof("remove me");
1421    lfs_file_close(&lfs, &file) => 0;
1422
1423    lfs_file_open(&lfs, &files[0], "/dir.1/0.before",
1424            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1425    lfs_file_open(&lfs, &files[1], "/dir.1/2.after",
1426            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1427    lfs_file_open(&lfs, &files[2], "/dir.2/0.before",
1428            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1429    lfs_file_open(&lfs, &files[3], "/dir.2/2.after",
1430            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1431    lfs_file_write(&lfs, &files[0], "test.9", 7) => 7;
1432    lfs_file_write(&lfs, &files[1], "test.a", 7) => 7;
1433    lfs_file_write(&lfs, &files[2], "test.b", 7) => 7;
1434    lfs_file_write(&lfs, &files[3], "test.c", 7) => 7;
1435
1436    // rename file while everything is open, this triggers both
1437    // a create and delete simultaneously
1438    lfs_rename(&lfs, "/dir.2/1.move_me", "/dir.1/1.move_me") => 0;
1439
1440    lfs_file_close(&lfs, &files[0]) => 0;
1441    lfs_file_close(&lfs, &files[1]) => 0;
1442    lfs_file_close(&lfs, &files[2]) => 0;
1443    lfs_file_close(&lfs, &files[3]) => 0;
1444
1445    // and check that nothing was corrupted again
1446    lfs_dir_open(&lfs, &dir, "/") => 0;
1447    lfs_dir_read(&lfs, &dir, &info) => 1;
1448    assert(strcmp(info.name, ".") == 0);
1449    assert(info.type == LFS_TYPE_DIR);
1450    lfs_dir_read(&lfs, &dir, &info) => 1;
1451    assert(strcmp(info.name, "..") == 0);
1452    assert(info.type == LFS_TYPE_DIR);
1453    lfs_dir_read(&lfs, &dir, &info) => 1;
1454    assert(strcmp(info.name, "dir.1") == 0);
1455    assert(info.type == LFS_TYPE_DIR);
1456    lfs_dir_read(&lfs, &dir, &info) => 1;
1457    assert(strcmp(info.name, "dir.2") == 0);
1458    assert(info.type == LFS_TYPE_DIR);
1459    lfs_dir_read(&lfs, &dir, &info) => 0;
1460    lfs_dir_close(&lfs, &dir) => 0;
1461
1462    lfs_dir_open(&lfs, &dir, "/dir.1") => 0;
1463    lfs_dir_read(&lfs, &dir, &info) => 1;
1464    assert(strcmp(info.name, ".") == 0);
1465    assert(info.type == LFS_TYPE_DIR);
1466    lfs_dir_read(&lfs, &dir, &info) => 1;
1467    assert(strcmp(info.name, "..") == 0);
1468    assert(info.type == LFS_TYPE_DIR);
1469    lfs_dir_read(&lfs, &dir, &info) => 1;
1470    assert(strcmp(info.name, "0.before") == 0);
1471    assert(info.type == LFS_TYPE_REG);
1472    assert(info.size == 7);
1473    lfs_dir_read(&lfs, &dir, &info) => 1;
1474    assert(strcmp(info.name, "1.move_me") == 0);
1475    assert(info.type == LFS_TYPE_REG);
1476    assert(info.size == 0);
1477    lfs_dir_read(&lfs, &dir, &info) => 1;
1478    assert(strcmp(info.name, "2.after") == 0);
1479    assert(info.type == LFS_TYPE_REG);
1480    assert(info.size == 7);
1481    lfs_dir_read(&lfs, &dir, &info) => 0;
1482    lfs_dir_close(&lfs, &dir) => 0;
1483
1484    lfs_dir_open(&lfs, &dir, "/dir.2") => 0;
1485    lfs_dir_read(&lfs, &dir, &info) => 1;
1486    assert(strcmp(info.name, ".") == 0);
1487    assert(info.type == LFS_TYPE_DIR);
1488    lfs_dir_read(&lfs, &dir, &info) => 1;
1489    assert(strcmp(info.name, "..") == 0);
1490    assert(info.type == LFS_TYPE_DIR);
1491    lfs_dir_read(&lfs, &dir, &info) => 1;
1492    assert(strcmp(info.name, "0.before") == 0);
1493    assert(info.type == LFS_TYPE_REG);
1494    assert(info.size == 7);
1495    lfs_dir_read(&lfs, &dir, &info) => 1;
1496    assert(strcmp(info.name, "2.after") == 0);
1497    assert(info.type == LFS_TYPE_REG);
1498    assert(info.size == 7);
1499    lfs_dir_read(&lfs, &dir, &info) => 0;
1500    lfs_dir_close(&lfs, &dir) => 0;
1501
1502    lfs_file_open(&lfs, &file, "/dir.1/0.before", LFS_O_RDONLY) => 0;
1503    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1504    assert(strcmp((char*)buffer, "test.9") == 0);
1505    lfs_file_close(&lfs, &file) => 0;
1506    lfs_file_open(&lfs, &file, "/dir.1/2.after", LFS_O_RDONLY) => 0;
1507    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1508    assert(strcmp((char*)buffer, "test.a") == 0);
1509    lfs_file_close(&lfs, &file) => 0;
1510    lfs_file_open(&lfs, &file, "/dir.2/0.before", LFS_O_RDONLY) => 0;
1511    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1512    assert(strcmp((char*)buffer, "test.b") == 0);
1513    lfs_file_close(&lfs, &file) => 0;
1514    lfs_file_open(&lfs, &file, "/dir.2/2.after", LFS_O_RDONLY) => 0;
1515    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1516    assert(strcmp((char*)buffer, "test.c") == 0);
1517    lfs_file_close(&lfs, &file) => 0;
1518    lfs_unmount(&lfs) => 0;
1519'''
1520
1521[[case]] # move fix in relocation
1522in = "lfs.c"
1523define.RELOCATIONS = 'range(0x3+1)'
1524define.LFS_ERASE_CYCLES = 0xffffffff
1525code = '''
1526    lfs_format(&lfs, &cfg) => 0;
1527    lfs_mount(&lfs, &cfg) => 0;
1528
1529    lfs_mkdir(&lfs, "/parent") => 0;
1530    lfs_mkdir(&lfs, "/parent/child") => 0;
1531
1532    lfs_file_open(&lfs, &file, "/parent/1.move_me",
1533            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1534    lfs_file_write(&lfs, &file, "move me",
1535            sizeof("move me")) => sizeof("move me");
1536    lfs_file_close(&lfs, &file) => 0;
1537
1538    lfs_file_open(&lfs, &file, "/parent/0.before",
1539            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1540    lfs_file_write(&lfs, &file, "test.1", 7) => 7;
1541    lfs_file_close(&lfs, &file) => 0;
1542    lfs_file_open(&lfs, &file, "/parent/2.after",
1543            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1544    lfs_file_write(&lfs, &file, "test.2", 7) => 7;
1545    lfs_file_close(&lfs, &file) => 0;
1546    lfs_file_open(&lfs, &file, "/parent/child/0.before",
1547            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1548    lfs_file_write(&lfs, &file, "test.3", 7) => 7;
1549    lfs_file_close(&lfs, &file) => 0;
1550    lfs_file_open(&lfs, &file, "/parent/child/2.after",
1551            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1552    lfs_file_write(&lfs, &file, "test.4", 7) => 7;
1553    lfs_file_close(&lfs, &file) => 0;
1554
1555    lfs_file_t files[4];
1556    lfs_file_open(&lfs, &files[0], "/parent/0.before",
1557            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1558    lfs_file_open(&lfs, &files[1], "/parent/2.after",
1559            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1560    lfs_file_open(&lfs, &files[2], "/parent/child/0.before",
1561            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1562    lfs_file_open(&lfs, &files[3], "/parent/child/2.after",
1563            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1564    lfs_file_write(&lfs, &files[0], "test.5", 7) => 7;
1565    lfs_file_write(&lfs, &files[1], "test.6", 7) => 7;
1566    lfs_file_write(&lfs, &files[2], "test.7", 7) => 7;
1567    lfs_file_write(&lfs, &files[3], "test.8", 7) => 7;
1568
1569    // force specific directories to relocate
1570    if (RELOCATIONS & 0x1) {
1571        lfs_dir_open(&lfs, &dir, "/parent");
1572        lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0;
1573        lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0;
1574        lfs_dir_close(&lfs, &dir) => 0;
1575    }
1576    if (RELOCATIONS & 0x2) {
1577        lfs_dir_open(&lfs, &dir, "/parent/child");
1578        lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0;
1579        lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0;
1580        lfs_dir_close(&lfs, &dir) => 0;
1581    }
1582
1583    // ok, now we move the file, this creates a move that needs to be
1584    // fixed, possibly in a metadata-pair that needs to be relocated
1585    //
1586    // the worst case is if we need to relocate and we need to implicit
1587    // fix the move in our parent before it falls out of date
1588    lfs_rename(&lfs, "/parent/1.move_me", "/parent/child/1.move_me") => 0;
1589
1590    lfs_file_close(&lfs, &files[0]) => 0;
1591    lfs_file_close(&lfs, &files[1]) => 0;
1592    lfs_file_close(&lfs, &files[2]) => 0;
1593    lfs_file_close(&lfs, &files[3]) => 0;
1594
1595    // check that nothing was corrupted
1596    lfs_dir_open(&lfs, &dir, "/parent") => 0;
1597    lfs_dir_read(&lfs, &dir, &info) => 1;
1598    assert(strcmp(info.name, ".") == 0);
1599    assert(info.type == LFS_TYPE_DIR);
1600    lfs_dir_read(&lfs, &dir, &info) => 1;
1601    assert(strcmp(info.name, "..") == 0);
1602    assert(info.type == LFS_TYPE_DIR);
1603    lfs_dir_read(&lfs, &dir, &info) => 1;
1604    assert(strcmp(info.name, "0.before") == 0);
1605    assert(info.type == LFS_TYPE_REG);
1606    assert(info.size == 7);
1607    lfs_dir_read(&lfs, &dir, &info) => 1;
1608    assert(strcmp(info.name, "2.after") == 0);
1609    assert(info.type == LFS_TYPE_REG);
1610    assert(info.size == 7);
1611    lfs_dir_read(&lfs, &dir, &info) => 1;
1612    assert(strcmp(info.name, "child") == 0);
1613    assert(info.type == LFS_TYPE_DIR);
1614    lfs_dir_read(&lfs, &dir, &info) => 0;
1615    lfs_dir_close(&lfs, &dir) => 0;
1616
1617    lfs_dir_open(&lfs, &dir, "/parent/child") => 0;
1618    lfs_dir_read(&lfs, &dir, &info) => 1;
1619    assert(strcmp(info.name, ".") == 0);
1620    assert(info.type == LFS_TYPE_DIR);
1621    lfs_dir_read(&lfs, &dir, &info) => 1;
1622    assert(strcmp(info.name, "..") == 0);
1623    assert(info.type == LFS_TYPE_DIR);
1624    lfs_dir_read(&lfs, &dir, &info) => 1;
1625    assert(strcmp(info.name, "0.before") == 0);
1626    assert(info.type == LFS_TYPE_REG);
1627    assert(info.size == 7);
1628    lfs_dir_read(&lfs, &dir, &info) => 1;
1629    assert(strcmp(info.name, "1.move_me") == 0);
1630    assert(info.type == LFS_TYPE_REG);
1631    assert(info.size == sizeof("move me"));
1632    lfs_dir_read(&lfs, &dir, &info) => 1;
1633    assert(strcmp(info.name, "2.after") == 0);
1634    assert(info.type == LFS_TYPE_REG);
1635    assert(info.size == 7);
1636    lfs_dir_read(&lfs, &dir, &info) => 0;
1637    lfs_dir_close(&lfs, &dir) => 0;
1638
1639    lfs_file_open(&lfs, &file, "/parent/0.before", LFS_O_RDONLY) => 0;
1640    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1641    assert(strcmp((char*)buffer, "test.5") == 0);
1642    lfs_file_close(&lfs, &file) => 0;
1643    lfs_file_open(&lfs, &file, "/parent/2.after", LFS_O_RDONLY) => 0;
1644    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1645    assert(strcmp((char*)buffer, "test.6") == 0);
1646    lfs_file_close(&lfs, &file) => 0;
1647    lfs_file_open(&lfs, &file, "/parent/child/0.before", LFS_O_RDONLY) => 0;
1648    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1649    assert(strcmp((char*)buffer, "test.7") == 0);
1650    lfs_file_close(&lfs, &file) => 0;
1651    lfs_file_open(&lfs, &file, "/parent/child/2.after", LFS_O_RDONLY) => 0;
1652    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1653    assert(strcmp((char*)buffer, "test.8") == 0);
1654    lfs_file_close(&lfs, &file) => 0;
1655    lfs_unmount(&lfs) => 0;
1656'''
1657
1658[[case]] # move fix in relocation with predecessor
1659in = "lfs.c"
1660define.RELOCATIONS = 'range(0x7+1)'
1661define.LFS_ERASE_CYCLES = 0xffffffff
1662code = '''
1663    lfs_format(&lfs, &cfg) => 0;
1664    lfs_mount(&lfs, &cfg) => 0;
1665
1666    lfs_mkdir(&lfs, "/parent") => 0;
1667    lfs_mkdir(&lfs, "/parent/child") => 0;
1668    lfs_mkdir(&lfs, "/parent/sibling") => 0;
1669
1670    lfs_file_open(&lfs, &file, "/parent/sibling/1.move_me",
1671            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1672    lfs_file_write(&lfs, &file, "move me",
1673            sizeof("move me")) => sizeof("move me");
1674    lfs_file_close(&lfs, &file) => 0;
1675
1676    lfs_file_open(&lfs, &file, "/parent/sibling/0.before",
1677            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1678    lfs_file_write(&lfs, &file, "test.1", 7) => 7;
1679    lfs_file_close(&lfs, &file) => 0;
1680    lfs_file_open(&lfs, &file, "/parent/sibling/2.after",
1681            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1682    lfs_file_write(&lfs, &file, "test.2", 7) => 7;
1683    lfs_file_close(&lfs, &file) => 0;
1684    lfs_file_open(&lfs, &file, "/parent/child/0.before",
1685            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1686    lfs_file_write(&lfs, &file, "test.3", 7) => 7;
1687    lfs_file_close(&lfs, &file) => 0;
1688    lfs_file_open(&lfs, &file, "/parent/child/2.after",
1689            LFS_O_WRONLY | LFS_O_CREAT) => 0;
1690    lfs_file_write(&lfs, &file, "test.4", 7) => 7;
1691    lfs_file_close(&lfs, &file) => 0;
1692
1693    lfs_file_t files[4];
1694    lfs_file_open(&lfs, &files[0], "/parent/sibling/0.before",
1695            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1696    lfs_file_open(&lfs, &files[1], "/parent/sibling/2.after",
1697            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1698    lfs_file_open(&lfs, &files[2], "/parent/child/0.before",
1699            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1700    lfs_file_open(&lfs, &files[3], "/parent/child/2.after",
1701            LFS_O_WRONLY | LFS_O_TRUNC) => 0;
1702    lfs_file_write(&lfs, &files[0], "test.5", 7) => 7;
1703    lfs_file_write(&lfs, &files[1], "test.6", 7) => 7;
1704    lfs_file_write(&lfs, &files[2], "test.7", 7) => 7;
1705    lfs_file_write(&lfs, &files[3], "test.8", 7) => 7;
1706
1707    // force specific directories to relocate
1708    if (RELOCATIONS & 0x1) {
1709        lfs_dir_open(&lfs, &dir, "/parent");
1710        lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0;
1711        lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0;
1712        lfs_dir_close(&lfs, &dir) => 0;
1713    }
1714    if (RELOCATIONS & 0x2) {
1715        lfs_dir_open(&lfs, &dir, "/parent/sibling");
1716        lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0;
1717        lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0;
1718        lfs_dir_close(&lfs, &dir) => 0;
1719    }
1720    if (RELOCATIONS & 0x4) {
1721        lfs_dir_open(&lfs, &dir, "/parent/child");
1722        lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0;
1723        lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0;
1724        lfs_dir_close(&lfs, &dir) => 0;
1725    }
1726
1727    // ok, now we move the file, this creates a move that needs to be
1728    // fixed, possibly in a metadata-pair that needs to be relocated
1729    //
1730    // and now relocations can force us to need to fix our move in either
1731    // the parent or child before things break
1732    lfs_rename(&lfs,
1733            "/parent/sibling/1.move_me",
1734            "/parent/child/1.move_me") => 0;
1735
1736    lfs_file_close(&lfs, &files[0]) => 0;
1737    lfs_file_close(&lfs, &files[1]) => 0;
1738    lfs_file_close(&lfs, &files[2]) => 0;
1739    lfs_file_close(&lfs, &files[3]) => 0;
1740
1741    // check that nothing was corrupted
1742    lfs_dir_open(&lfs, &dir, "/parent") => 0;
1743    lfs_dir_read(&lfs, &dir, &info) => 1;
1744    assert(strcmp(info.name, ".") == 0);
1745    assert(info.type == LFS_TYPE_DIR);
1746    lfs_dir_read(&lfs, &dir, &info) => 1;
1747    assert(strcmp(info.name, "..") == 0);
1748    assert(info.type == LFS_TYPE_DIR);
1749    lfs_dir_read(&lfs, &dir, &info) => 1;
1750    assert(strcmp(info.name, "child") == 0);
1751    assert(info.type == LFS_TYPE_DIR);
1752    lfs_dir_read(&lfs, &dir, &info) => 1;
1753    assert(strcmp(info.name, "sibling") == 0);
1754    assert(info.type == LFS_TYPE_DIR);
1755    lfs_dir_read(&lfs, &dir, &info) => 0;
1756    lfs_dir_close(&lfs, &dir) => 0;
1757
1758    lfs_dir_open(&lfs, &dir, "/parent/sibling") => 0;
1759    lfs_dir_read(&lfs, &dir, &info) => 1;
1760    assert(strcmp(info.name, ".") == 0);
1761    assert(info.type == LFS_TYPE_DIR);
1762    lfs_dir_read(&lfs, &dir, &info) => 1;
1763    assert(strcmp(info.name, "..") == 0);
1764    assert(info.type == LFS_TYPE_DIR);
1765    lfs_dir_read(&lfs, &dir, &info) => 1;
1766    assert(strcmp(info.name, "0.before") == 0);
1767    assert(info.type == LFS_TYPE_REG);
1768    assert(info.size == 7);
1769    lfs_dir_read(&lfs, &dir, &info) => 1;
1770    assert(strcmp(info.name, "2.after") == 0);
1771    assert(info.type == LFS_TYPE_REG);
1772    assert(info.size == 7);
1773    lfs_dir_read(&lfs, &dir, &info) => 0;
1774    lfs_dir_close(&lfs, &dir) => 0;
1775
1776    lfs_dir_open(&lfs, &dir, "/parent/child") => 0;
1777    lfs_dir_read(&lfs, &dir, &info) => 1;
1778    assert(strcmp(info.name, ".") == 0);
1779    assert(info.type == LFS_TYPE_DIR);
1780    lfs_dir_read(&lfs, &dir, &info) => 1;
1781    assert(strcmp(info.name, "..") == 0);
1782    assert(info.type == LFS_TYPE_DIR);
1783    lfs_dir_read(&lfs, &dir, &info) => 1;
1784    assert(strcmp(info.name, "0.before") == 0);
1785    assert(info.type == LFS_TYPE_REG);
1786    assert(info.size == 7);
1787    lfs_dir_read(&lfs, &dir, &info) => 1;
1788    assert(strcmp(info.name, "1.move_me") == 0);
1789    assert(info.type == LFS_TYPE_REG);
1790    assert(info.size == sizeof("move me"));
1791    lfs_dir_read(&lfs, &dir, &info) => 1;
1792    assert(strcmp(info.name, "2.after") == 0);
1793    assert(info.type == LFS_TYPE_REG);
1794    assert(info.size == 7);
1795    lfs_dir_read(&lfs, &dir, &info) => 0;
1796    lfs_dir_close(&lfs, &dir) => 0;
1797
1798    lfs_file_open(&lfs, &file, "/parent/sibling/0.before", LFS_O_RDONLY) => 0;
1799    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1800    assert(strcmp((char*)buffer, "test.5") == 0);
1801    lfs_file_close(&lfs, &file) => 0;
1802    lfs_file_open(&lfs, &file, "/parent/sibling/2.after", LFS_O_RDONLY) => 0;
1803    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1804    assert(strcmp((char*)buffer, "test.6") == 0);
1805    lfs_file_close(&lfs, &file) => 0;
1806    lfs_file_open(&lfs, &file, "/parent/child/0.before", LFS_O_RDONLY) => 0;
1807    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1808    assert(strcmp((char*)buffer, "test.7") == 0);
1809    lfs_file_close(&lfs, &file) => 0;
1810    lfs_file_open(&lfs, &file, "/parent/child/2.after", LFS_O_RDONLY) => 0;
1811    lfs_file_read(&lfs, &file, buffer, 7) => 7;
1812    assert(strcmp((char*)buffer, "test.8") == 0);
1813    lfs_file_close(&lfs, &file) => 0;
1814    lfs_unmount(&lfs) => 0;
1815'''
1816