Skip to content

fix: exFAT scan truncation and ScanStageProperties migration - #1381

Merged
wizzomafizzo merged 2 commits into
mainfrom
fix/exfat-symlink-scan-truncation
Sep 2, 2026
Merged

fix: exFAT scan truncation and ScanStageProperties migration#1381
wizzomafizzo merged 2 commits into
mainfrom
fix/exfat-symlink-scan-truncation

Conversation

@wizzomafizzo

@wizzomafizzo wizzomafizzo commented Sep 1, 2026

Copy link
Copy Markdown
Member
  • The symlink-excluded and symlink-alias branches in GetFiles returned filepath.SkipDir, which fastwalk only honours for an entry it typed as a directory or a symlink. Returned for anything else it escapes readDir and aborts iteration of the whole containing directory, silently dropping every entry after the alias.
  • On exFAT and FAT the dirent carries no symlink bit, so direntTypesReportSymlinks is false and entryIsSymlink finds links by lstat while fastwalk still sees a regular file. A MiSTer log from a user carried 1450 truncated directories under _Arcade/_alternatives, each losing the alternative MRAs that followed the alias.
  • skipEntry now returns the sentinel only when fastwalk will act on it and nil otherwise, which is the correct skip for an entry fastwalk never descends into. walk_skipdir_test could not catch this because it runs on ext4, where the dirent is typed and fastwalk's own escape hatch applies; the new cases cover the untyped entry and pin the upstream behaviour being worked around.
  • ScanStageProperties and its index only ever existed because sqlClearScanStage failed on the missing table and called sqlEnsureScanStagingTables to repair the scratch schema, so every fresh media.db took that error path on its first system. They now have a migration. The repair path stays for copied and partially migrated databases, and IF NOT EXISTS keeps it a no-op elsewhere.
  • TestMigrations_BrowseSortCollationBumpsVersionWithoutTableWork used a bare goose.Down, which reverts whichever migration happens to be last, so it only tested the collation downgrade while that migration was newest. It now uses DownTo against the version before it.

Summary by CodeRabbit

  • Bug Fixes

    • Improved media scanning on FAT and exFAT volumes so symlink aliases no longer stop directory traversal or hide neighboring media files.
    • Added database migration support for scan-stage properties, improving recovery and consistency during scanning.
  • Tests

    • Expanded coverage for symlink handling, directory traversal, and migration rollback behavior.

fastwalk only honours filepath.SkipDir for an entry it typed as a
directory or a symlink. Returned for anything else it escapes readDir
and aborts iteration of the whole containing directory, dropping every
entry after it.

On exFAT and FAT the dirent carries no symlink bit, so
direntTypesReportSymlinks is false and entryIsSymlink finds links by
lstat while fastwalk still sees a regular file. The symlink-excluded
and symlink-alias branches then skipped the rest of the directory
instead of the one entry. A MiSTer log carried 1450 truncated
directories under _Arcade/_alternatives, each losing the alternative
MRAs that followed the alias.

skipEntry returns the sentinel only when fastwalk will act on it, and
nil otherwise, which is the correct skip for an entry fastwalk never
descends into. The existing walk_skipdir_test could not catch this: it
runs on ext4, where the dirent is typed and fastwalk's own escape hatch
applies.
The table and its index were only ever created because sqlClearScanStage
failed on the missing table, logged "scan staging tables missing;
recreating scratch schema" and called sqlEnsureScanStagingTables to
repair it. Every fresh media.db took that error path on its first
system. The repair path stays for copied and partially migrated
databases; IF NOT EXISTS keeps it a no-op elsewhere.

TestMigrations_BrowseSortCollationBumpsVersionWithoutTableWork used a
bare goose.Down, which reverts whichever migration happens to be last,
so it only tested the collation downgrade while that migration was
newest. It now uses DownTo against the version before it.
@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 4ad962b2-6167-481c-9075-56bf4d1848a7

📥 Commits

Reviewing files that changed from the base of the PR and between 4023de5 and 1402935.

📒 Files selected for processing (4)
  • pkg/database/mediadb/mediadb_integration_test.go
  • pkg/database/mediadb/migrations/20260901120000_scan_stage_properties.sql
  • pkg/database/mediascanner/mediascanner.go
  • pkg/database/mediascanner/walk_skipdir_test.go

Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review.


📝 Walkthrough

Walkthrough

The changes add a ScanStageProperties database migration, target a specific migration version in integration tests, and prevent media scanning from truncating directories when symlinks are reported as regular files.

Changes

Media database migrations

Layer / File(s) Summary
ScanStageProperties migration and downgrade targeting
pkg/database/mediadb/migrations/20260901120000_scan_stage_properties.sql, pkg/database/mediadb/mediadb_integration_test.go
The migration creates the ScanStageProperties table and property index. The integration test downgrades explicitly to the version before the browse-sort-collation migration.

Media scanner traversal

Layer / File(s) Summary
Conditional entry skipping
pkg/database/mediascanner/mediascanner.go
skipEntry returns filepath.SkipDir for directories and symlinks, and nil for regular-file entries. Excluded directories and symlink aliases use this helper.
Traversal regression coverage
pkg/database/mediascanner/walk_skipdir_test.go
Tests verify skipEntry results and confirm that untyped alias entries preserve sibling traversal with one and four workers.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to 14029

The change prevents exFAT and FAT scans from stopping early after excluded symlink aliases and creates scan-staging schema during migration while preserving recovery behavior for incomplete databases. No actionable merge-blocking risk remains after normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant fastwalk
  participant filesystem
  participant skipEntry
  fastwalk->>filesystem: Read directory entries
  fastwalk->>skipEntry: Evaluate alias entry
  skipEntry-->>fastwalk: Return nil for regular-file dirent
  fastwalk->>filesystem: Continue reading sibling media
  skipEntry-->>fastwalk: Return filepath.SkipDir for directory or symlink
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely identifies both primary changes: the exFAT scan truncation fix and the ScanStageProperties migration.
Docstring Coverage ✅ Passed Docstring coverage is 90.91% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 3 files. (1 skipped: 1 …
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.
Full details: Docstring Coverage

Explanation

Docstring coverage is 90.91% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 3 files. (1 skipped: 1 unsupported.)

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/exfat-symlink-scan-truncation

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.

@codecov

codecov Bot commented Sep 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@wizzomafizzo
wizzomafizzo merged commit 2f40a51 into main Sep 2, 2026
18 checks passed
@wizzomafizzo
wizzomafizzo deleted the fix/exfat-symlink-scan-truncation branch September 2, 2026 01:11
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