Skip to content

Commit a1d8a76

Browse files
committed
Added correct handling of file syncing around overwrites
Now all of the open flags are correctly handled Even annoying cases where we can't trust the blocks that are already on file, such as appending existing files and writing to the middle of files.
1 parent a4e9132 commit a1d8a76

File tree

2 files changed

+98
-30
lines changed

2 files changed

+98
-30
lines changed

lfs.c

Lines changed: 95 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ static int lfs_bd_read(lfs_t *lfs, lfs_block_t block,
8282
// load to cache, first condition can no longer fail
8383
lfs->rcache.block = block;
8484
lfs->rcache.off = off - (off % lfs->cfg->read_size);
85-
// TODO remove reading, should be unnecessary
8685
err = lfs->cfg->read(lfs->cfg, lfs->rcache.block,
8786
lfs->rcache.off, lfs->cfg->read_size,
8887
lfs->rcache.buffer);
@@ -141,12 +140,6 @@ static int lfs_bd_prog(lfs_t *lfs, lfs_block_t block,
141140
// prepare cache, first condition can no longer fail
142141
lfs->pcache.block = block;
143142
lfs->pcache.off = off - (off % lfs->cfg->prog_size);
144-
err = lfs->cfg->read(lfs->cfg, lfs->pcache.block,
145-
lfs->pcache.off, lfs->cfg->prog_size,
146-
lfs->pcache.buffer);
147-
if (err) {
148-
return err;
149-
}
150143
}
151144

152145
return 0;
@@ -810,7 +803,7 @@ static int lfs_index_find(lfs_t *lfs, lfs_block_t head, lfs_size_t size,
810803
lfs_off_t current = lfs_index(lfs, &(lfs_off_t){size-1});
811804
lfs_off_t target = lfs_index(lfs, &pos);
812805

813-
while (current != target) {
806+
while (current > target) {
814807
lfs_size_t skip = lfs_min(
815808
lfs_npw2(current-target+1) - 1,
816809
lfs_min(lfs_ctz(current)+1, lfs->words-1) - 1);
@@ -831,6 +824,7 @@ static int lfs_index_find(lfs_t *lfs, lfs_block_t head, lfs_size_t size,
831824
static int lfs_index_extend(lfs_t *lfs,
832825
lfs_block_t head, lfs_size_t size,
833826
lfs_off_t *block, lfs_block_t *off) {
827+
// go ahead and grab a block
834828
int err = lfs_alloc(lfs, block);
835829
if (err) {
836830
return err;
@@ -846,11 +840,35 @@ static int lfs_index_extend(lfs_t *lfs,
846840
return 0;
847841
}
848842

849-
lfs_off_t index = lfs_index(lfs, &(lfs_off_t){size-1}) + 1;
843+
size -= 1;
844+
lfs_off_t index = lfs_index(lfs, &size);
845+
size += 1;
846+
847+
// just copy out the last block if it is incomplete
848+
if (size != lfs->cfg->block_size) {
849+
for (lfs_off_t i = 0; i < size; i++) {
850+
uint8_t data;
851+
int err = lfs_bd_read(lfs, head, i, 1, &data);
852+
if (err) {
853+
return err;
854+
}
855+
856+
err = lfs_bd_prog(lfs, *block, i, 1, &data);
857+
if (err) {
858+
return err;
859+
}
860+
}
861+
862+
*off = size;
863+
return 0;
864+
}
865+
866+
// append block
867+
index += 1;
850868
lfs_size_t skips = lfs_min(lfs_ctz(index)+1, lfs->words-1);
851869

852870
for (lfs_off_t i = 0; i < skips; i++) {
853-
err = lfs_bd_prog(lfs, *block, 4*i, 4, &head);
871+
int err = lfs_bd_prog(lfs, *block, 4*i, 4, &head);
854872
if (err) {
855873
return err;
856874
}
@@ -936,27 +954,68 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
936954
return LFS_ERROR_EXISTS;
937955
}
938956

939-
file->head = file->entry.d.u.file.head;
940-
file->size = file->entry.d.u.file.size;
941-
file->wpos = file->entry.d.u.file.size;
957+
file->wpos = 0;
942958
file->wblock = 0;
943959
file->rpos = 0;
944960
file->rblock = 0;
945961

962+
if (flags & LFS_O_TRUNC) {
963+
file->entry.d.u.file.head = 0;
964+
file->entry.d.u.file.size = 0;
965+
}
966+
967+
if (flags & LFS_O_APPEND) {
968+
file->wpos = file->entry.d.u.file.size;
969+
}
970+
946971
return 0;
947972
}
948973

949974
int lfs_file_close(lfs_t *lfs, lfs_file_t *file) {
950-
// Store file
975+
return lfs_file_sync(lfs, file);
976+
}
977+
978+
int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
979+
if (file->wblock == 0) {
980+
// already in sync, may be rdonly
981+
return 0;
982+
}
983+
984+
// copy over anything after the file
985+
lfs_off_t oldrpos = file->rpos;
986+
lfs_off_t oldwpos = file->wpos;
987+
file->rpos = file->wpos;
988+
file->rblock = 0;
989+
990+
while (file->wpos < file->entry.d.u.file.size) {
991+
uint8_t data;
992+
lfs_ssize_t res = lfs_file_read(lfs, file, &data, 1);
993+
if (res < 0) {
994+
return res;
995+
}
996+
997+
res = lfs_file_write(lfs, file, &data, 1);
998+
if (res < 0) {
999+
return res;
1000+
}
1001+
}
1002+
1003+
// actual file updates
1004+
file->entry.d.u.file.head = file->wblock;
1005+
file->entry.d.u.file.size = file->wpos;
1006+
1007+
file->rpos = oldrpos;
1008+
file->rblock = 0;
1009+
file->wpos = oldwpos;
1010+
file->wblock = 0;
1011+
1012+
// update dir entry
9511013
lfs_dir_t cwd;
9521014
int err = lfs_dir_fetch(lfs, &cwd, file->entry.pair);
9531015
if (err) {
9541016
return err;
9551017
}
9561018

957-
file->entry.d.u.file.head = file->head;
958-
file->entry.d.u.file.size = file->size;
959-
9601019
return lfs_dir_commit(lfs, &cwd, &file->entry, NULL);
9611020
}
9621021

@@ -966,14 +1025,16 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
9661025
lfs_size_t nsize = size;
9671026

9681027
while (nsize > 0) {
1028+
// check if we need a new block
9691029
if (!file->wblock || file->woff == lfs->cfg->block_size) {
970-
int err = lfs_index_extend(lfs, file->head, file->wpos,
1030+
int err = lfs_index_extend(lfs, file->wblock, file->wpos,
9711031
&file->wblock, &file->woff);
9721032
if (err) {
9731033
return err;
9741034
}
9751035
}
9761036

1037+
// program as much as we can in current block
9771038
lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->woff);
9781039
int err = lfs_bd_prog(lfs, file->wblock, file->woff, diff, data);
9791040
if (err) {
@@ -985,9 +1046,16 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
9851046
data += diff;
9861047
nsize -= diff;
9871048

988-
if (file->wpos > file->size) {
989-
file->size = file->wpos;
990-
file->head = file->wblock;
1049+
if (file->flags & LFS_O_APPEND) {
1050+
file->entry.d.u.file.head = file->wblock;
1051+
file->entry.d.u.file.size = file->wpos;
1052+
}
1053+
}
1054+
1055+
if (file->flags & LFS_O_SYNC) {
1056+
int err = lfs_file_sync(lfs, file);
1057+
if (err) {
1058+
return err;
9911059
}
9921060
}
9931061

@@ -997,18 +1065,21 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
9971065
lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
9981066
void *buffer, lfs_size_t size) {
9991067
uint8_t *data = buffer;
1000-
size = lfs_min(size, file->size - file->rpos);
1068+
size = lfs_min(size, file->entry.d.u.file.size - file->rpos);
10011069
lfs_size_t nsize = size;
10021070

10031071
while (nsize > 0) {
1072+
// check if we need a new block
10041073
if (!file->rblock || file->roff == lfs->cfg->block_size) {
1005-
int err = lfs_index_find(lfs, file->head, file->size, file->rpos,
1006-
&file->rblock, &file->roff);
1074+
int err = lfs_index_find(lfs,
1075+
file->entry.d.u.file.head, file->entry.d.u.file.size,
1076+
file->rpos, &file->rblock, &file->roff);
10071077
if (err) {
10081078
return err;
10091079
}
10101080
}
10111081

1082+
// read as much as we can in current block
10121083
lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->roff);
10131084
int err = lfs_bd_read(lfs, file->rblock, file->roff, diff, data);
10141085
if (err) {

lfs.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,8 @@ typedef struct lfs_entry {
122122
} lfs_entry_t;
123123

124124
typedef struct lfs_file {
125-
lfs_block_t head;
126-
lfs_size_t size;
125+
struct lfs_entry entry;
126+
int flags;
127127

128128
lfs_off_t wpos;
129129
lfs_block_t wblock;
@@ -132,10 +132,6 @@ typedef struct lfs_file {
132132
lfs_off_t rpos;
133133
lfs_block_t rblock;
134134
lfs_off_t roff;
135-
136-
int flags;
137-
138-
struct lfs_entry entry;
139135
} lfs_file_t;
140136

141137
typedef struct lfs_dir {
@@ -203,6 +199,7 @@ int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info);
203199
int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
204200
const char *path, int flags);
205201
int lfs_file_close(lfs_t *lfs, lfs_file_t *file);
202+
int lfs_file_sync(lfs_t *lfs, lfs_file_t *file);
206203
lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
207204
const void *buffer, lfs_size_t size);
208205
lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,

0 commit comments

Comments
 (0)