Merge branch 'fix/fatfs-vfs-fcntl-setfl_v6.0_2' into 'release/v6.0'

fix(fatfs): preserve access mode in VFS F_SETFL (v6.0)

See merge request espressif/esp-idf!51922
This commit is contained in:
Martin Vychodil
2026-09-10 16:07:28 +08:00
4 changed files with 47 additions and 2 deletions

View File

@@ -195,6 +195,13 @@ TEST_CASE("(WL) overwrite and append file", "[fatfs][wear_levelling]")
test_teardown();
}
TEST_CASE("(WL) fcntl F_SETFL preserves access mode", "[fatfs][wear_levelling]")
{
test_setup();
test_fatfs_fcntl_setfl("/spiflash/fcntl.txt");
test_teardown();
}
TEST_CASE("(WL) can lseek", "[fatfs][wear_levelling]")
{
test_setup();

View File

@@ -94,6 +94,37 @@ void test_fatfs_overwrite_append(const char* filename)
TEST_ASSERT_EQUAL(0, fclose(f_r));
}
void test_fatfs_fcntl_setfl(const char* filename)
{
unlink(filename);
int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC);
TEST_ASSERT_NOT_EQUAL(-1, fd);
int flags = fcntl(fd, F_GETFL);
TEST_ASSERT_NOT_EQUAL(-1, flags);
TEST_ASSERT_EQUAL(O_RDWR, flags & O_ACCMODE);
TEST_ASSERT_EQUAL(0, flags & O_APPEND);
/* F_SETFL must not clobber O_ACCMODE when arg is only a status flag. */
TEST_ASSERT_EQUAL(0, fcntl(fd, F_SETFL, O_APPEND));
flags = fcntl(fd, F_GETFL);
TEST_ASSERT_EQUAL(O_RDWR, flags & O_ACCMODE);
TEST_ASSERT_NOT_EQUAL(0, flags & O_APPEND);
TEST_ASSERT_EQUAL(4, write(fd, "AAAA", 4));
TEST_ASSERT_NOT_EQUAL(-1, lseek(fd, 0, SEEK_SET));
TEST_ASSERT_EQUAL(4, write(fd, "BBBB", 4));
TEST_ASSERT_EQUAL(0, close(fd));
char buf[10] = { 0 };
FILE *f_r = fopen(filename, "r");
TEST_ASSERT_NOT_NULL(f_r);
TEST_ASSERT_EQUAL(8, fread(buf, 1, 8, f_r));
TEST_ASSERT_EQUAL_STRING_LEN("AAAABBBB", buf, 8);
TEST_ASSERT_EQUAL(0, fclose(f_r));
unlink(filename);
}
void test_fatfs_read_file(const char* filename)
{
FILE* f = fopen(filename, "r");

View File

@@ -33,6 +33,8 @@ void test_fatfs_open_file_with_o_creat_flag(const char* filename);
void test_fatfs_overwrite_append(const char* filename);
void test_fatfs_fcntl_setfl(const char* filename);
void test_fatfs_read_file(const char* filename);
void test_fatfs_read_file_utf_8(const char* filename);

View File

@@ -705,8 +705,13 @@ static int vfs_fat_fcntl(void* ctx, int fd, int cmd, int arg)
switch (cmd) {
case F_GETFL:
return fat_ctx->flags[fd];
case F_SETFL:
fat_ctx->flags[fd] = arg;
case F_SETFL: {
/* POSIX: F_SETFL changes status flags only; access mode is immutable.
* FatFS honors O_APPEND on write(). O_NONBLOCK is stored for F_GETFL
* round-trip but does not make I/O non-blocking. */
const uint32_t setfl_mask = (uint32_t)(O_APPEND | O_NONBLOCK);
fat_ctx->flags[fd] = (fat_ctx->flags[fd] & ~setfl_mask) | ((uint32_t)arg & setfl_mask);
}
return 0;
// no-ops:
case F_SETLK: