Skip to content
Open
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
155 changes: 121 additions & 34 deletions dfs_lfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,30 @@
#include <stdio.h>
#include <string.h>

#if defined(RT_VERSION_CHECK) && (RTTHREAD_VERSION >= RT_VERSION_CHECK(5, 0, 2))
#if defined(DFS_OFF_MAX)
#define DFS_LFS_DFS_OFF_TYPE dfs_off_t
#define DFS_LFS_FILE_OFF_TYPE dfs_off_t
#define DFS_LFS_STAT_TYPE struct dfs_stat
#define DFS_LFS_STAT_MTIME(st) ((st)->mtime)
#elif defined(RT_USING_DFS_V2)
#define DFS_LFS_DFS_OFF_TYPE off_t
#define DFS_LFS_FILE_OFF_TYPE off_t
#define DFS_LFS_STAT_TYPE struct stat
#define DFS_LFS_STAT_MTIME(st) ((st)->st_mtime)
#else
#define DFS_LFS_DFS_OFF_TYPE off_t
#define DFS_LFS_FILE_OFF_TYPE rt_off_t
#define DFS_LFS_STAT_TYPE struct stat
#define DFS_LFS_STAT_MTIME(st) ((st)->st_mtime)
#endif

#if defined(DFS_OFF_MAX) || (defined(RT_VERSION_CHECK) && (RTTHREAD_VERSION >= RT_VERSION_CHECK(5, 0, 2)))
#define DFS_LFS_RW_RETURN_TYPE ssize_t
#define DFS_LFS_LSK_RETURN_TYPE off_t
#define DFS_LFS_LSK_RETURN_TYPE DFS_LFS_DFS_OFF_TYPE
#else
#define DFS_LFS_RW_RETURN_TYPE int
#define DFS_LFS_LSK_RETURN_TYPE int
#endif /* defined(RT_VERSION_CHECK) && (RTTHREAD_VERSION >= RT_VERSION_CHECK(5, 0, 2)) */
#endif /* defined(DFS_OFF_MAX) || (defined(RT_VERSION_CHECK) && (RTTHREAD_VERSION >= RT_VERSION_CHECK(5, 0, 2))) */

#if defined(RT_USING_DFS_V2) || (defined(RT_VERSION_CHECK) && (RTTHREAD_VERSION >= RT_VERSION_CHECK(5, 0, 0)))
#define DFS_LFS_MKFS_PARAMS rt_device_t dev_id, const char *fs_name
Expand Down Expand Up @@ -59,12 +76,12 @@
#define DFS_LFS_FILE_REF_COUNT(file) ((file)->vnode->ref_count)
#define DFS_LFS_FILE_IS_VALID(file) ((file)->vnode != RT_NULL)
#define DFS_LFS_FILE_FS(file) ((file)->dentry->mnt)
#define DFS_LFS_READ_PARAMS DFS_LFS_FILE_STRUCT* file, void* buf, size_t len, off_t* pos
#define DFS_LFS_WRITE_PARAMS DFS_LFS_FILE_STRUCT* file, const void* buf, size_t len, off_t* pos
#define DFS_LFS_LSEEK_PARAMS DFS_LFS_FILE_STRUCT* file, off_t offset, int whence
#define DFS_LFS_READ_PARAMS DFS_LFS_FILE_STRUCT* file, void* buf, size_t len, DFS_LFS_DFS_OFF_TYPE* pos
#define DFS_LFS_WRITE_PARAMS DFS_LFS_FILE_STRUCT* file, const void* buf, size_t len, DFS_LFS_DFS_OFF_TYPE* pos
#define DFS_LFS_LSEEK_PARAMS DFS_LFS_FILE_STRUCT* file, DFS_LFS_DFS_OFF_TYPE offset, int whence
#define DFS_LFS_IO_POS_PARAM pos
#define DFS_LFS_LSEEK_WHENCE whence
#define DFS_LFS_STORE_FILE_POS(file, pos, lfs_pos) (*(pos) = (off_t)(lfs_pos))
#define DFS_LFS_STORE_FILE_POS(file, pos, lfs_pos) (*(pos) = (DFS_LFS_DFS_OFF_TYPE)(lfs_pos))
#define DFS_LFS_REGISTER() dfs_register(&_dfs_lfs_type)
#elif defined(RT_VERSION_CHECK) && (RTTHREAD_VERSION >= RT_VERSION_CHECK(5, 0, 2))
/**
Expand All @@ -85,10 +102,10 @@
#define DFS_LFS_FILE_FS(file) ((file)->vnode->fs)
#define DFS_LFS_READ_PARAMS DFS_LFS_FILE_STRUCT* file, void* buf, size_t len
#define DFS_LFS_WRITE_PARAMS DFS_LFS_FILE_STRUCT* file, const void* buf, size_t len
#define DFS_LFS_LSEEK_PARAMS DFS_LFS_FILE_STRUCT* file, rt_off_t offset
#define DFS_LFS_LSEEK_PARAMS DFS_LFS_FILE_STRUCT* file, DFS_LFS_FILE_OFF_TYPE offset
#define DFS_LFS_IO_POS_PARAM RT_NULL
#define DFS_LFS_LSEEK_WHENCE SEEK_SET
#define DFS_LFS_STORE_FILE_POS(file, pos, lfs_pos) (DFS_LFS_FILE_POS(file) = (rt_off_t)(lfs_pos))
#define DFS_LFS_STORE_FILE_POS(file, pos, lfs_pos) (DFS_LFS_FILE_POS(file) = (DFS_LFS_FILE_OFF_TYPE)(lfs_pos))
#define DFS_LFS_FS_FLAGS DFS_FS_FLAG_DEFAULT
#define DFS_LFS_REGISTER() dfs_register(&_dfs_lfs_ops)
#elif defined(RT_USING_DFS_V1)
Expand All @@ -114,10 +131,10 @@
#define DFS_LFS_FILE_FS(file) ((file)->vnode->fs)
#define DFS_LFS_READ_PARAMS DFS_LFS_FILE_STRUCT* file, void* buf, size_t len
#define DFS_LFS_WRITE_PARAMS DFS_LFS_FILE_STRUCT* file, const void* buf, size_t len
#define DFS_LFS_LSEEK_PARAMS DFS_LFS_FILE_STRUCT* file, rt_off_t offset
#define DFS_LFS_LSEEK_PARAMS DFS_LFS_FILE_STRUCT* file, DFS_LFS_FILE_OFF_TYPE offset
#define DFS_LFS_IO_POS_PARAM RT_NULL
#define DFS_LFS_LSEEK_WHENCE SEEK_SET
#define DFS_LFS_STORE_FILE_POS(file, pos, lfs_pos) (DFS_LFS_FILE_POS(file) = (rt_off_t)(lfs_pos))
#define DFS_LFS_STORE_FILE_POS(file, pos, lfs_pos) (DFS_LFS_FILE_POS(file) = (DFS_LFS_FILE_OFF_TYPE)(lfs_pos))
#define DFS_LFS_FS_FLAGS DFS_FS_FLAG_DEFAULT
#define DFS_LFS_REGISTER() dfs_register(&_dfs_lfs_ops)
#elif defined(RT_VERSION_CHECK) && (RTTHREAD_VERSION >= RT_VERSION_CHECK(5, 0, 0))
Expand All @@ -142,10 +159,10 @@
#define DFS_LFS_FILE_FS(file) ((file)->vnode->fs)
#define DFS_LFS_READ_PARAMS DFS_LFS_FILE_STRUCT* file, void* buf, size_t len
#define DFS_LFS_WRITE_PARAMS DFS_LFS_FILE_STRUCT* file, const void* buf, size_t len
#define DFS_LFS_LSEEK_PARAMS DFS_LFS_FILE_STRUCT* file, rt_off_t offset
#define DFS_LFS_LSEEK_PARAMS DFS_LFS_FILE_STRUCT* file, DFS_LFS_FILE_OFF_TYPE offset
#define DFS_LFS_IO_POS_PARAM RT_NULL
#define DFS_LFS_LSEEK_WHENCE SEEK_SET
#define DFS_LFS_STORE_FILE_POS(file, pos, lfs_pos) (DFS_LFS_FILE_POS(file) = (rt_off_t)(lfs_pos))
#define DFS_LFS_STORE_FILE_POS(file, pos, lfs_pos) (DFS_LFS_FILE_POS(file) = (DFS_LFS_FILE_OFF_TYPE)(lfs_pos))
#define DFS_LFS_FS_FLAGS DFS_FS_FLAG_DEFAULT
#define DFS_LFS_REGISTER() dfs_register(&_dfs_lfs_ops)
#else
Expand All @@ -170,10 +187,10 @@
#define DFS_LFS_FILE_FS(file) ((file)->fs)
#define DFS_LFS_READ_PARAMS DFS_LFS_FILE_STRUCT* file, void* buf, size_t len
#define DFS_LFS_WRITE_PARAMS DFS_LFS_FILE_STRUCT* file, const void* buf, size_t len
#define DFS_LFS_LSEEK_PARAMS DFS_LFS_FILE_STRUCT* file, rt_off_t offset
#define DFS_LFS_LSEEK_PARAMS DFS_LFS_FILE_STRUCT* file, DFS_LFS_FILE_OFF_TYPE offset
#define DFS_LFS_IO_POS_PARAM RT_NULL
#define DFS_LFS_LSEEK_WHENCE SEEK_SET
#define DFS_LFS_STORE_FILE_POS(file, pos, lfs_pos) (DFS_LFS_FILE_POS(file) = (rt_off_t)(lfs_pos))
#define DFS_LFS_STORE_FILE_POS(file, pos, lfs_pos) (DFS_LFS_FILE_POS(file) = (DFS_LFS_FILE_OFF_TYPE)(lfs_pos))
#define DFS_LFS_FS_FLAGS DFS_FS_FLAG_DEFAULT
#define DFS_LFS_REGISTER() dfs_register(&_dfs_lfs_ops)
#endif /* defined(RT_USING_DFS_V2) */
Expand Down Expand Up @@ -406,6 +423,10 @@ static int _lfs_result_to_dfs(int result)
status = -ENOMEM;
break; // No more memory available

case LFS_ERR_FBIG:
status = -EFBIG;
break; // File too large

case LFS_ERR_CORRUPT:
status = -52;
break; // Corrupted
Expand All @@ -418,10 +439,41 @@ static int _lfs_result_to_dfs(int result)
return status;
}

static int _dfs_lfs_check_lfs_range(int64_t offset)
{
if (offset < 0 || offset > (DFS_LFS_DFS_OFF_TYPE)LFS_FILE_MAX)
{
return -EINVAL;
}

return RT_EOK;
}

#if defined(RT_USING_DFS_V2)
static int _dfs_lfs_add_file_off(DFS_LFS_FILE_OFF_TYPE base,
DFS_LFS_FILE_OFF_TYPE delta,
DFS_LFS_FILE_OFF_TYPE* result)
{
if (base < 0)
{
return -EINVAL;
}

if ((delta > 0 && base > (DFS_LFS_FILE_OFF_TYPE)LFS_FILE_MAX - delta)
|| (delta < 0 && delta < -base))
{
return -EINVAL;
}

*result = base + delta;
return RT_EOK;
}
#endif /* defined(RT_USING_DFS_V2) */

/* DFS v2 passes read/write offsets explicitly. Keep DFS v1 behavior unchanged. */
static int _dfs_lfs_sync_file_pos(DFS_LFS_FILE_STRUCT* file,
dfs_lfs_fd_t* dfs_lfs_fd,
off_t* pos)
DFS_LFS_DFS_OFF_TYPE* pos)
{
#if defined(RT_USING_DFS_V2)
lfs_soff_t current;
Expand All @@ -432,7 +484,13 @@ static int _dfs_lfs_sync_file_pos(DFS_LFS_FILE_STRUCT* file,
RT_ASSERT(dfs_lfs_fd != RT_NULL);
RT_ASSERT(pos != RT_NULL);

result = _dfs_lfs_check_lfs_range((int64_t)*pos);
if (result < 0)
{
return result;
}
target = (lfs_soff_t)*pos;

current = lfs_file_tell(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file);
if (current < 0)
{
Expand Down Expand Up @@ -696,9 +754,9 @@ static int _dfs_lfs_unlink(DFS_LFS_MNT_TYPE* dfs, const char* path)
}
#endif

static void _dfs_lfs_tostat(struct stat* st, struct lfs_info* info, time_t mtime)
static void _dfs_lfs_tostat(DFS_LFS_STAT_TYPE* st, struct lfs_info* info, time_t mtime)
{
memset(st, 0, sizeof(struct stat));
memset(st, 0, sizeof(DFS_LFS_STAT_TYPE));

/* convert to dfs stat structure */
st->st_dev = 0;
Expand All @@ -716,10 +774,10 @@ static void _dfs_lfs_tostat(struct stat* st, struct lfs_info* info, time_t mtime
break;
}

st->st_mtime = mtime;
DFS_LFS_STAT_MTIME(st) = mtime;
}

static int _dfs_lfs_stat(DFS_LFS_MNT_TYPE* dfs, const char* path, struct stat* st)
static int _dfs_lfs_stat(DFS_LFS_MNT_TYPE* dfs, const char* path, DFS_LFS_STAT_TYPE* st)
{
dfs_lfs_t* dfs_lfs;
int result;
Expand Down Expand Up @@ -938,8 +996,9 @@ static int _dfs_lfs_ioctl(DFS_LFS_FILE_STRUCT* file, int cmd, void* args)
return -EROFS;
#else
dfs_lfs_fd_t *dfs_lfs_fd;
off_t length;
DFS_LFS_DFS_OFF_TYPE length;
int result;
lfs_off_t lfs_size;
lfs_soff_t pos;

RT_ASSERT(file != RT_NULL);
Expand All @@ -960,15 +1019,17 @@ static int _dfs_lfs_ioctl(DFS_LFS_FILE_STRUCT* file, int cmd, void* args)
return -EBADF;
}

length = *(off_t *)args;
if (length < 0)
length = *(DFS_LFS_DFS_OFF_TYPE *)args;
result = _dfs_lfs_check_lfs_range((int64_t)length);
if (result < 0)
{
return -EINVAL;
return result;
}
lfs_size = (lfs_off_t)length;

dfs_lfs_fd = (dfs_lfs_fd_t *)file->data;

result = lfs_file_truncate(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, (lfs_off_t)length);
result = lfs_file_truncate(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, lfs_size);
if (result < 0)
{
return _lfs_result_to_dfs(result);
Expand All @@ -979,14 +1040,14 @@ static int _dfs_lfs_ioctl(DFS_LFS_FILE_STRUCT* file, int cmd, void* args)
{
return _lfs_result_to_dfs((int)pos);
}
DFS_LFS_FILE_POS(file) = (rt_off_t)pos;
DFS_LFS_FILE_POS(file) = (DFS_LFS_FILE_OFF_TYPE)pos;

pos = lfs_file_size(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file);
if (pos < 0)
{
return _lfs_result_to_dfs((int)pos);
}
DFS_LFS_FILE_SIZE(file) = (rt_off_t)pos;
DFS_LFS_FILE_SIZE(file) = (DFS_LFS_FILE_OFF_TYPE)pos;

return RT_EOK;
#endif
Expand All @@ -1000,7 +1061,7 @@ static int _dfs_lfs_ioctl(DFS_LFS_FILE_STRUCT* file, int cmd, void* args)
}

#if defined(RT_USING_DFS_V2) && !defined(LFS_READONLY)
static int _dfs_lfs_truncate(DFS_LFS_FILE_STRUCT* file, off_t length)
static int _dfs_lfs_truncate(DFS_LFS_FILE_STRUCT* file, DFS_LFS_DFS_OFF_TYPE length)
{
return _dfs_lfs_ioctl(file, RT_FIOFTRUNCATE, &length);
}
Expand Down Expand Up @@ -1100,6 +1161,8 @@ static int _dfs_lfs_flush(DFS_LFS_FILE_STRUCT* file)
static DFS_LFS_LSK_RETURN_TYPE _dfs_lfs_lseek(DFS_LFS_LSEEK_PARAMS)
{
dfs_lfs_fd_t* dfs_lfs_fd;
lfs_soff_t lfs_offset;
int result;

RT_ASSERT(file != RT_NULL);
RT_ASSERT(file->data != RT_NULL);
Expand All @@ -1112,10 +1175,18 @@ static DFS_LFS_LSK_RETURN_TYPE _dfs_lfs_lseek(DFS_LFS_LSEEK_PARAMS)
case SEEK_SET:
break;
case SEEK_CUR:
offset += DFS_LFS_FILE_POS(file);
result = _dfs_lfs_add_file_off(DFS_LFS_FILE_POS(file), offset, &offset);
if (result < 0)
{
return result;
}
break;
case SEEK_END:
offset += DFS_LFS_FILE_SIZE(file);
result = _dfs_lfs_add_file_off(DFS_LFS_FILE_SIZE(file), offset, &offset);
if (result < 0)
{
return result;
}
break;
default:
return -EINVAL;
Expand All @@ -1124,7 +1195,16 @@ static DFS_LFS_LSK_RETURN_TYPE _dfs_lfs_lseek(DFS_LFS_LSEEK_PARAMS)

if (DFS_LFS_FILE_TYPE(file) == FT_REGULAR)
{
lfs_soff_t soff = lfs_file_seek(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, offset, LFS_SEEK_SET);
lfs_soff_t soff;

result = _dfs_lfs_check_lfs_range((int64_t)offset);
if (result < 0)
{
return result;
}
lfs_offset = (lfs_soff_t)offset;

soff = lfs_file_seek(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, lfs_offset, LFS_SEEK_SET);
if (soff < 0)
{
return _lfs_result_to_dfs((int)soff);
Expand All @@ -1137,6 +1217,7 @@ static DFS_LFS_LSK_RETURN_TYPE _dfs_lfs_lseek(DFS_LFS_LSEEK_PARAMS)
lfs_off_t off;
lfs_soff_t soff;
DFS_LFS_LSK_RETURN_TYPE dirent_size;
DFS_LFS_FILE_OFF_TYPE entry_index;

dirent_size = (DFS_LFS_LSK_RETURN_TYPE)sizeof(struct dirent);
if ((offset < 0) || ((offset % dirent_size) != 0))
Expand All @@ -1145,7 +1226,13 @@ static DFS_LFS_LSK_RETURN_TYPE _dfs_lfs_lseek(DFS_LFS_LSEEK_PARAMS)
}

/* skip . and .. */
off = (lfs_off_t)(offset / dirent_size) + 2;
entry_index = (DFS_LFS_FILE_OFF_TYPE)(offset / dirent_size);
if (entry_index > (DFS_LFS_FILE_OFF_TYPE)((lfs_off_t)-1 - 2))
{
return -EINVAL;
}

off = (lfs_off_t)entry_index + 2;
Comment on lines +1229 to +1235

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Locate rt_off_t / off_t definitions to confirm signed 32-bit configurations exist.
rg -nP '\b(typedef|`#define`)\b.*\b(rt_off_t|off_t)\b'
fd -t f -e h | rg -l 'rt_off_t' | head

Repository: RT-Thread-packages/littlefs

Length of output: 165


🏁 Script executed:

# First, let's locate the dfs_lfs.c file and verify the code snippet
fd -t f -e c | rg 'dfs_lfs' | head -20

Repository: RT-Thread-packages/littlefs

Length of output: 175


🏁 Script executed:

# Search more broadly for type definitions and includes
rg -n 'DFS_LFS_FILE_OFF_TYPE|lfs_off_t' -t c -t h | head -30

Repository: RT-Thread-packages/littlefs

Length of output: 165


🏁 Script executed:

# Look for rt_off_t in header files with broader search
rg 'rt_off_t|off_t' -t h | head -40

Repository: RT-Thread-packages/littlefs

Length of output: 165


🏁 Script executed:

# Find and read the dfs_lfs.c file
fd -t f 'dfs_lfs\.c'

Repository: RT-Thread-packages/littlefs

Length of output: 175


🏁 Script executed:

# Once we have the file, let's look for it and read the relevant lines
git ls-files | grep -E '(dfs_lfs|\.c$)' | head -20

Repository: RT-Thread-packages/littlefs

Length of output: 455


🏁 Script executed:

# Look for any file containing these types
rg 'DFS_LFS_FILE_OFF_TYPE' --type c --type h -l

Repository: RT-Thread-packages/littlefs

Length of output: 165


🏁 Script executed:

# Read the dfs_lfs.c file to see the code context
wc -l dfs_lfs.c

Repository: RT-Thread-packages/littlefs

Length of output: 180


🏁 Script executed:

# Read around lines 1229-1235
sed -n '1220,1245p' dfs_lfs.c

Repository: RT-Thread-packages/littlefs

Length of output: 1074


🏁 Script executed:

# Look for type definitions and includes at the beginning of dfs_lfs.c
head -100 dfs_lfs.c | grep -E 'typedef|include|define.*off'

Repository: RT-Thread-packages/littlefs

Length of output: 744


🏁 Script executed:

# Find lfs_off_t definition
rg 'typedef.*lfs_off_t|lfs_off_t.*=' -A 2 dfs_lfs.c lfs.h

Repository: RT-Thread-packages/littlefs

Length of output: 242


🏁 Script executed:

# Look for off_t and rt_off_t definitions
rg 'typedef.*off_t|typedef.*rt_off_t' -t h

Repository: RT-Thread-packages/littlefs

Length of output: 165


🏁 Script executed:

# Get more context around the DFS_LFS_FILE_OFF_TYPE definitions to understand the conditionals
sed -n '1,50p' dfs_lfs.c

Repository: RT-Thread-packages/littlefs

Length of output: 1903


🏁 Script executed:

# Search for conditional compilation around the typedef block
grep -n -B 10 -A 2 'DFS_LFS_FILE_OFF_TYPE' dfs_lfs.c | head -60

Repository: RT-Thread-packages/littlefs

Length of output: 3840


🏁 Script executed:

# Search in included headers for rt_off_t and off_t definitions
# These are likely in RT-Thread system headers, but let's check what we have available
rg 'typedef.*rt_off_t|typedef.*off_t' -i -t h --type-add 'headers:include'

Repository: RT-Thread-packages/littlefs

Length of output: 165


🏁 Script executed:

# Look at what rtthread.h includes
grep -r 'typedef.*off_t' --include='*.h' | head -20

Repository: RT-Thread-packages/littlefs

Length of output: 234


🏁 Script executed:

# Check if there are any documentation or comments about type sizes
grep -r 'int32_t.*off_t\|signed.*off_t\|32.*bit' --include='*.h' --include='*.c' | grep -i off | head -20

Repository: RT-Thread-packages/littlefs

Length of output: 234


🏁 Script executed:

# Let's verify the mathematical logic: compute what (uint32_t)-1 - 2 becomes when cast to int32_t
python3 - <<'PY'
# lfs_off_t is uint32_t (unsigned 32-bit)
lfs_off_t_value = (0xFFFFFFFF - 2) & 0xFFFFFFFF  # (uint32_t)-1 - 2
print(f"(lfs_off_t)-1 - 2 = 0x{lfs_off_t_value:08X} = {lfs_off_t_value}")

# When cast to int32_t (signed 32-bit)
import ctypes
signed_value = ctypes.c_int32(lfs_off_t_value).value
print(f"When cast to int32_t: {signed_value}")

# Test the comparison
entry_index = 0
print(f"\nComparison: entry_index ({entry_index}) > cast_value ({signed_value}) = {entry_index > signed_value}")
entry_index = 1000
print(f"Comparison: entry_index ({entry_index}) > cast_value ({signed_value}) = {entry_index > signed_value}")
PY

Repository: RT-Thread-packages/littlefs

Length of output: 344


🏁 Script executed:

# Search for any context about rt_off_t in comments or documentation
rg 'rt_off_t' -B 3 -A 3 --include='*.c' --include='*.h' --include='*.md'

Repository: RT-Thread-packages/littlefs

Length of output: 607


🏁 Script executed:

# Verify the proposed fix logic
python3 - <<'PY'
# Proposed fix: if ((uint64_t)entry_index > (uint64_t)((lfs_off_t)-1) - 2)

# First, compute the bound in unsigned 64-bit
lfs_off_t_max_val = 0xFFFFFFFF  # (lfs_off_t)-1, which is uint32_t max
bound = lfs_off_t_max_val - 2  # = 0xFFFFFFFD = 4294967293
print(f"Bound in uint64_t: {bound} (0x{bound:016X})")

# Test with various entry_index values
test_values = [0, 1, 2, 100, 4294967291, 4294967293, 4294967294, 4294967295]
print("\nProposed fix comparison: (uint64_t)entry_index > bound")
for val in test_values:
    result = val > bound
    print(f"  entry_index={val}: {val} > {bound} = {result}")

# Also test with original broken logic for comparison
print("\nBroken logic: entry_index > (int32_t)((uint32_t)-1 - 2)")
cast_val = -3
for val in test_values:
    result = val > cast_val
    print(f"  entry_index={val}: {val} > {cast_val} = {result}")
PY

Repository: RT-Thread-packages/littlefs

Length of output: 1047


🏁 Script executed:

# Look for any existing bug reports or comments about this in the code
grep -r 'bound\|overflow\|seek.*off' --include='*.c' --include='*.h' dfs_lfs.c | grep -i 'entry\|directory' | head -10

Repository: RT-Thread-packages/littlefs

Length of output: 165


Directory-seek bound check always rejects valid offsets on signed 32-bit off types.

When DFS_LFS_FILE_OFF_TYPE is rt_off_t (a signed 32-bit type used in legacy DFS v1), the expression (DFS_LFS_FILE_OFF_TYPE)((lfs_off_t)-1 - 2) casts 0xFFFFFFFD from unsigned 32-bit to signed 32-bit, resulting in -3. Since entry_index is non-negative, the comparison entry_index > -3 is always true, causing the function to return -EINVAL for every directory seek operation.

Apply the proposed fix to compare in unsigned 64-bit domain instead:

Fix
     /* skip . and .. */
     entry_index = (DFS_LFS_FILE_OFF_TYPE)(offset / dirent_size);
-    if (entry_index > (DFS_LFS_FILE_OFF_TYPE)((lfs_off_t)-1 - 2))
+    if ((uint64_t)entry_index > (uint64_t)((lfs_off_t)-1) - 2)
     {
         return -EINVAL;
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dfs_lfs.c` around lines 1229 - 1235, The bound check comparison for
entry_index around line 1230 is incorrectly casting an unsigned 64-bit value to
a signed 32-bit type, resulting in -3 instead of the intended upper bound. This
causes the condition to always evaluate to true for valid offsets. Fix this by
casting entry_index to lfs_off_t (unsigned 64-bit) before comparing it to
(lfs_off_t)((lfs_off_t)-1 - 2), ensuring the entire comparison happens in the
unsigned 64-bit domain where the bound check works correctly regardless of
whether DFS_LFS_FILE_OFF_TYPE is signed or unsigned.

soff = lfs_dir_seek(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.dir, off);
if (soff < 0)
{
Expand Down Expand Up @@ -1272,7 +1359,7 @@ static int _dfs_lfs_dentry_rename(struct dfs_dentry* old_dentry, struct dfs_dent
}
#endif /* !defined(LFS_READONLY) */

static int _dfs_lfs_dentry_stat(struct dfs_dentry* dentry, struct stat* st)
static int _dfs_lfs_dentry_stat(struct dfs_dentry* dentry, DFS_LFS_STAT_TYPE* st)
{
RT_ASSERT(dentry != RT_NULL);
RT_ASSERT(dentry->mnt != RT_NULL);
Expand All @@ -1283,7 +1370,7 @@ static int _dfs_lfs_dentry_stat(struct dfs_dentry* dentry, struct stat* st)
static struct dfs_vnode* _dfs_lfs_lookup(struct dfs_dentry* dentry)
{
struct dfs_vnode* vnode;
struct stat st;
DFS_LFS_STAT_TYPE st;

if (dentry == RT_NULL || dentry->mnt == RT_NULL || dentry->mnt->data == RT_NULL)
{
Expand Down