Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to LFS v1.7.2 tag - to fix filesystem corruption due to file renames #831

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 37 additions & 35 deletions libraries/Adafruit_LittleFS/src/littlefs/lfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -888,7 +888,7 @@ static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir,
}

// check that entry has not been moved
if (entry->d.type & 0x80) {
if (!lfs->moving && entry->d.type & 0x80) {
int moved = lfs_moved(lfs, &entry->d.u);
if (moved < 0 || moved) {
return (moved < 0) ? moved : LFS_ERR_NOENT;
Expand Down Expand Up @@ -1644,6 +1644,11 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
file->pos = file->size;
}

if (file->pos + size > LFS_FILE_MAX) {
// larger than file limit?
return LFS_ERR_FBIG;
}

if (!(file->flags & LFS_F_WRITING) && file->pos > file->size) {
// fill with zeros
lfs_off_t pos = file->pos;
Expand Down Expand Up @@ -1730,24 +1735,24 @@ lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file,
return err;
}

// update pos
// find new pos
lfs_soff_t npos = file->pos;
if (whence == LFS_SEEK_SET) {
file->pos = off;
npos = off;
} else if (whence == LFS_SEEK_CUR) {
if (off < 0 && (lfs_off_t)-off > file->pos) {
return LFS_ERR_INVAL;
}

file->pos = file->pos + off;
npos = file->pos + off;
} else if (whence == LFS_SEEK_END) {
if (off < 0 && (lfs_off_t)-off > file->size) {
return LFS_ERR_INVAL;
}
npos = file->size + off;
}

file->pos = file->size + off;
if (npos < 0 || npos > LFS_FILE_MAX) {
// file position out of range
return LFS_ERR_INVAL;
}

return file->pos;
// update pos
file->pos = npos;
return npos;
}

int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
Expand Down Expand Up @@ -1924,7 +1929,14 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
// find old entry
lfs_dir_t oldcwd;
lfs_entry_t oldentry;
int err = lfs_dir_find(lfs, &oldcwd, &oldentry, &oldpath);
int err = lfs_dir_find(lfs, &oldcwd, &oldentry, &(const char *){oldpath});
if (err) {
return err;
}

// mark as moving
oldentry.d.type |= 0x80;
err = lfs_dir_update(lfs, &oldcwd, &oldentry, NULL);
if (err) {
return err;
}
Expand All @@ -1937,11 +1949,9 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
return err;
}

bool prevexists = (err != LFS_ERR_NOENT);
bool samepair = (lfs_paircmp(oldcwd.pair, newcwd.pair) == 0);

// must have same type
if (prevexists && preventry.d.type != oldentry.d.type) {
bool prevexists = (err != LFS_ERR_NOENT);
if (prevexists && preventry.d.type != (0x7f & oldentry.d.type)) {
return LFS_ERR_ISDIR;
}

Expand All @@ -1953,21 +1963,9 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
err = lfs_dir_fetch(lfs, &dir, preventry.d.u.dir);
if (err) {
return err;
} else if (dir.d.size != sizeof(dir.d)+4) {
} else if (dir.d.size != sizeof(dir.d)+4) {
return LFS_ERR_NOTEMPTY;
}
}

// mark as moving
oldentry.d.type |= 0x80;
err = lfs_dir_update(lfs, &oldcwd, &oldentry, NULL);
if (err) {
return err;
}

// update pair if newcwd == oldcwd
if (samepair) {
newcwd = oldcwd;
}
}

// move to new location
Expand All @@ -1988,10 +1986,13 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
}
}

// update pair if newcwd == oldcwd
if (samepair) {
oldcwd = newcwd;
// fetch old pair again in case dir block changed
lfs->moving = true;
err = lfs_dir_find(lfs, &oldcwd, &oldentry, &oldpath);
if (err) {
return err;
}
lfs->moving = false;

// remove old entry
err = lfs_dir_remove(lfs, &oldcwd, &oldentry);
Expand Down Expand Up @@ -2089,6 +2090,7 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
lfs->files = NULL;
lfs->dirs = NULL;
lfs->deorphaned = false;
lfs->moving = false;

return 0;

Expand Down
9 changes: 8 additions & 1 deletion libraries/Adafruit_LittleFS/src/littlefs/lfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ extern "C"
// Software library version
// Major (top-nibble), incremented on backwards incompatible changes
// Minor (bottom-nibble), incremented on feature additions
#define LFS_VERSION 0x00010006
#define LFS_VERSION 0x00010007
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))

Expand Down Expand Up @@ -49,6 +49,11 @@ typedef uint32_t lfs_block_t;
#define LFS_NAME_MAX 255
#endif

// Max file size in bytes
#ifndef LFS_FILE_MAX
#define LFS_FILE_MAX 2147483647
#endif

// Possible error codes, these are negative to allow
// valid positive return values
enum lfs_error {
Expand All @@ -61,6 +66,7 @@ enum lfs_error {
LFS_ERR_ISDIR = -21, // Entry is a dir
LFS_ERR_NOTEMPTY = -39, // Dir is not empty
LFS_ERR_BADF = -9, // Bad file number
LFS_ERR_FBIG = -27, // File too large
LFS_ERR_INVAL = -22, // Invalid parameter
LFS_ERR_NOSPC = -28, // No space left on device
LFS_ERR_NOMEM = -12, // No more memory available
Expand Down Expand Up @@ -280,6 +286,7 @@ typedef struct lfs {

lfs_free_t free;
bool deorphaned;
bool moving;
} lfs_t;


Expand Down
Loading