diff --git a/lfs.c b/lfs.c index 4c135aa..4cad04c 100644 --- a/lfs.c +++ b/lfs.c @@ -1183,6 +1183,50 @@ int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { return err; } +static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { +relocate: + LFS_DEBUG("Bad block at %d", file->block); + + // just relocate what exists into new block + lfs_block_t nblock; + int err = lfs_alloc(lfs, &nblock); + if (err) { + return err; + } + + // either read from dirty cache or disk + for (lfs_off_t i = 0; i < file->off; i++) { + uint8_t data; + if (file->cache.block == file->block && i >= file->cache.off) { + data = file->cache.buffer[i - file->cache.off]; + } else { + // just read from disk + err = lfs_bd_read(lfs, file->block, i, &data, 1); + if (err) { + return err; + } + } + + err = lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache, + nblock, i, &data, 1); + if (err) { + if (err == LFS_ERR_CORRUPT) { + goto relocate; + } + return err; + } + } + + // copy over new state of file + memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->prog_size); + file->cache.block = lfs->pcache.block; + file->cache.off = lfs->pcache.off; + lfs->pcache.block = 0xffffffff; + + file->block = nblock; + return 0; +} + static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { if (file->flags & LFS_F_READING) { // just drop read cache @@ -1225,9 +1269,21 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { } // write out what we have - int err = lfs_cache_flush(lfs, &file->cache, &lfs->rcache); - if (err) { - return err; + while (true) { + int err = lfs_cache_flush(lfs, &file->cache, &lfs->rcache); + if (err) { + if (err == LFS_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + break; +relocate: + err = lfs_file_relocate(lfs, file); + if (err) { + return err; + } } // actual file updates @@ -1396,45 +1452,10 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, break; relocate: - LFS_DEBUG("Bad block at %d", file->block); - - // just relocate what exists into new block - lfs_block_t nblock; - err = lfs_alloc(lfs, &nblock); + err = lfs_file_relocate(lfs, file); if (err) { return err; } - - // either read from dirty cache or disk - for (lfs_off_t i = 0; i < file->off; i++) { - uint8_t data; - if (file->cache.block == file->block && i >= file->cache.off) { - data = file->cache.buffer[i - file->cache.off]; - } else { - // just read from disk - err = lfs_bd_read(lfs, file->block, i, &data, 1); - if (err) { - return err; - } - } - - err = lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache, - nblock, i, &data, 1); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - } - - // copy over new state of file - memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->prog_size); - file->cache.block = lfs->pcache.block; - file->cache.off = lfs->pcache.off; - lfs->pcache.block = 0xffffffff; - - file->block = nblock; } file->pos += diff;