Skip to content

增加大文件支持需求#38

Open
LZerro wants to merge 1 commit into
RT-Thread-packages:masterfrom
LZerro:LZerro_adapt_dfs
Open

增加大文件支持需求#38
LZerro wants to merge 1 commit into
RT-Thread-packages:masterfrom
LZerro:LZerro_adapt_dfs

Conversation

@LZerro

@LZerro LZerro commented Jun 23, 2026

Copy link
Copy Markdown

Summary by CodeRabbit

Bug Fixes

  • Enhanced file offset validation with range checking to prevent invalid operations
  • Improved error handling for large file operations
  • Refined file seek and truncate operations with safer offset computations
  • Strengthened metadata handling consistency across different system versions

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

dfs_lfs.c gains new compatibility macros (DFS_LFS_DFS_OFF_TYPE, DFS_LFS_FILE_OFF_TYPE, DFS_LFS_STAT_TYPE, DFS_LFS_STAT_MTIME) centralizing offset and stat types across DFS v1/v2 and RT-Thread version branches. A new _dfs_lfs_check_lfs_range() helper validates offsets before lseek, truncate, and sync operations, and LFS_ERR_FBIG is mapped to -EFBIG.

Changes

LittleFS offset type safety and range validation

Layer / File(s) Summary
Compatibility type and ABI macros
dfs_lfs.c
Defines DFS_LFS_DFS_OFF_TYPE, DFS_LFS_FILE_OFF_TYPE, DFS_LFS_STAT_TYPE, DFS_LFS_STAT_MTIME, DFS_LFS_RW_RETURN_TYPE, and DFS_LFS_LSK_RETURN_TYPE for all DFS/RT version branches; applies new offset types to lseek parameter and position-storage macros in every version branch.
Range-check helper and sync_file_pos integration
dfs_lfs.c
Adds _dfs_lfs_check_lfs_range() to gate int64_t offsets against LFS_FILE_MAX; integrates it into _dfs_lfs_sync_file_pos() with updated DFS_LFS_DFS_OFF_TYPE* parameter; adds LFS_ERR_FBIG-EFBIG error mapping.
Truncate ioctl and _dfs_lfs_truncate() hardening
dfs_lfs.c
Changes RT_FIOFTRUNCATE ioctl to read length as DFS_LFS_DFS_OFF_TYPE, range-checks it, converts to lfs_off_t before lfs_file_truncate(), and writes back position/size via DFS_LFS_FILE_OFF_TYPE casts; updates DFS v2 _dfs_lfs_truncate() signature.
lseek range validation and directory seek bounds
dfs_lfs.c
Introduces lfs_soff_t lfs_offset; uses _dfs_lfs_add_file_off() for SEEK_CUR/SEEK_END under DFS v2; adds range-check before lfs_file_seek(); introduces bounded entry_index for directory seek with overflow guard against (lfs_off_t)-1 - 2.
Stat type migration
dfs_lfs.c
Updates _dfs_lfs_tostat(), _dfs_lfs_stat(), _dfs_lfs_dentry_stat(), and _dfs_lfs_lookup() to use DFS_LFS_STAT_TYPE and DFS_LFS_STAT_MTIME() instead of struct stat and direct st_mtime access.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • Rbb666
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title "增加大文件支持需求" (Add large file support requirements) is directly related to the main objective of the changeset. The PR introduces offset type handling, range validation, and file position macros specifically to support larger file operations.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch LZerro_adapt_dfs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with 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.

Inline comments:
In `@dfs_lfs.c`:
- Around line 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.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d33a9d9b-8157-40c0-b7f4-1ba37e7cd920

📥 Commits

Reviewing files that changed from the base of the PR and between bf5beae and f1e0e4e.

📒 Files selected for processing (1)
  • dfs_lfs.c

Comment thread dfs_lfs.c
Comment on lines +1229 to +1235
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;

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant