Skip to content

Implement the 2026-10-07 improvement backlog (2.0.0) - #121

Merged
indy2kro merged 30 commits into
mainfrom
feat/improvement-backlog-2026-10-07
Oct 7, 2026
Merged

indy2kro merged 30 commits into
mainfrom
feat/improvement-backlog-2026-10-07

Conversation

@indy2kro

@indy2kro indy2kro commented Oct 7, 2026

Copy link
Copy Markdown
Owner

Implements every item of the second improvement audit, docs/improvement-audit/2026-10-07-improvement-backlog.md: 44 items, all ticked. The backlog document is included in this PR.

This targets 2.0.0. It contains BC breaks, which are listed in CHANGELOG.md and explained with before/after snippets in UPGRADE-2.0.md.

Highlights

Parsing fixes

  • Partition descriptor location and size are now read as 32-bit both-byte-order values. The test builder used to encode the same mistake.
  • An ISO 9660:1999 Enhanced Volume Descriptor or a non-Joliet SVD is no longer decoded as UTF-16. New getEnhancedVolume().
  • On bridge images whose ISO 9660 tree is only a stub (Windows install ISOs), getFileSystem() now returns the UDF file system.
  • Names lose the ;N version and the trailing separator dot (README.;1 becomes README).
  • The Joliet ASCII fallback no longer garbles CJK strings.
  • Associated files are skipped, and data after an extended attribute record is read correctly.
  • Multi-extent files keep their Rock Ridge data.
  • getFullPath() always uses /.

Robustness

  • Volume descriptors must carry the CD001 identifier and are capped at 64.
  • Truncated images give a clear error.
  • UDF tag checksum and location are verified, and extents are bounded by the partition length.
  • Rock Ridge: CE handling fixed and SP len_skp honoured.
  • Impossible dates are rejected and out-of-range GMT offsets ignored.
  • SafePath rejects Windows reserved names and characters.

Features

  • UDF 2.50 metadata partitions.
  • UDF symlinks, owner and permissions, and Rock Ridge TF/PN.
  • IsoEntry gains uid, gid, mode and symlinkTarget.
  • find() reads only the directories on the path (listDirectory()).
  • openStream() is a lazy, seekable stream (Util\EntryStream).
  • El Torito boot image size and extraction; catalogs spanning several sectors are read.
  • Extractor keeps file times, with preserveMode and continueOnError/getErrors().
  • WalkWarnings makes incomplete listings detectable, with a strict mode that throws.
  • All exposed dates are now CarbonImmutable.

CLI

  • New options: --volume=primary|joliet|udf, --no-rock-ridge, --files, --ndjson, --extract-boot, --strict.
  • Two actions at once is a usage error.
  • Short flags can be bundled (-lj).
  • A missing --file exits with code 1.

Tests, CI and docs

  • Four real-world fixtures, generated with xorriso/genisoimage in Docker (fixtures/build-fixtures.sh): Rock Ridge, ISO 9660:1999, Joliet CJK, and names without extension.
  • A deterministic fuzz test, which found and fixed one PHP warning in 17-byte dates.
  • Cross-checks between the test builders and real images, and edge-case tests.
  • New Windows CI job; PHPStan memory limit; tests:coverage works with Xdebug; dev files are export-ignored.
  • SECURITY.md now points to private vulnerability reporting.
  • Refreshed README, new CHANGELOG.md and UPGRADE-2.0.md.

Main BC breaks

  • Dates are CarbonImmutable.
  • FileSystem gained listDirectory() and getEntryRanges(), and an optional WalkWarnings parameter on walk, listDirectory, find and search.
  • Volume::walk($isoFile, $depth, $warnings, $rockRidge): Rock Ridge is now the last parameter.
  • Name normalisation.
  • getSupplementaryVolume() returns only Joliet descriptors.
  • CLI info output no longer lists files without --files.

Known limits

  • UDF: no metadata mirror fallback, and sparable or VAT partitions are reported as unsupported.
  • UDF metadata partitions are tested only on synthetic images, not on a real Blu-ray image.
  • The preserveMode chmod test is skipped on Windows.
  • The new Windows CI job has not run yet.

Verification

composer run check passes: phpcs, phpstan, rector and phpunit (608 tests, 2196 assertions, 1 skipped on Windows). composer audit, gitleaks and actionlint are clean. Line coverage is 97.1%.

🤖 Generated with Claude Code

Second audit round: 44 open items (bugs, robustness, features, UX, CI/docs). No source changes.
…n SafePath and search

ROB-02, FEAT-04, FEAT-05, UX-06
…Ridge, path table separator

Strip any version suffix and the separator dot of extension-less names,
skip associated files, start file data after the extended attribute
record, keep Rock Ridge data of multi-extent files, and always use '/'
in path table paths.
… stub fallback, Joliet fallback, raw getBytes, header checks)

Partition location/size are both-byte-order, only Joliet SVDs are UTF-16, add getEnhancedVolume(), prefer UDF over a stub ISO 9660 tree, stricter ASCII fallback in Buffer::getString, Buffer::getBytes returns raw bytes, CD001 check, descriptor cap, clear truncated image error, idempotent openFile().
…ata partitions

ROB-03: descriptor tags are verified (checksum and location); a failing descriptor is treated as absent.
ROB-06: partition lengths are recorded and extents leaving their partition are treated as corrupt.
FEAT-01: UDF 2.50 metadata partition maps are read through the allocation extents of the metadata file;
sparable and virtual maps are reported by name.
…args; El Torito image size and extraction

UX-01 --volume and --no-rock-ridge, UX-02 --files opt-in, UX-03 conflicting actions and bundled flags, UX-05 --list --ndjson, FEAT-03 boot image size, extractImage, multi-sector catalogs, --extract-boot.
…ignore out-of-range GMT offsets

SWEEP-01: every exposed date is now Carbon\CarbonImmutable (IsoDate, Volume, FileDirectory, IsoEntry, RockRidgeInfo, UdfNode), so descriptors cannot be mutated through their properties.
BUG-10: IsoDate::createWithOffsetMinutes validates with checkdate().
ROB-07: GMT offsets outside -48..+52 (15 min units) or -720..+780 minutes are treated as UTC instead of dropping the date.
…penStream

- UDF: decode symlink targets, skip devices/FIFOs/sockets (BUG-11)
- IsoEntry: symlinkTarget, uid, gid, mode from UDF and Rock Ridge PX (FEAT-07)
- FileSystem::listDirectory() and getEntryRanges(); find() descends per component (FEAT-02)
- openStream() reads lazily through the EntryStream wrapper (FEAT-06)
…sotool --strict)

walk(), listDirectory(), find(), search() and Extractor::extract() accept an optional
WalkWarnings collector recording depth limits, unreadable/too large/truncated directories,
corrupt directory records and UDF root/entry errors. Volume::walk/listDirectory take the
collector as third parameter (before bool \$rockRidge\) to stay compatible with FileSystem.
isotool prints them as WARNING: lines on stderr; --strict fails on the first one.
@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 752 complexity · 0 duplication

Metric Results
Complexity 752
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@codecov

codecov Bot commented Oct 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.11664% with 22 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.42%. Comparing base (931ca0a) to head (d34ba39).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/Udf/UdfFileSystem.php 94.37% 9 Missing ⚠️
src/Util/EntryStream.php 92.20% 6 Missing ⚠️
src/Util/Buffer.php 80.00% 2 Missing ⚠️
src/Cli/IsoTool.php 98.90% 1 Missing ⚠️
src/Descriptor/BootCatalog.php 97.56% 1 Missing ⚠️
src/Descriptor/RockRidge.php 98.36% 1 Missing ⚠️
src/Descriptor/Volume.php 98.86% 1 Missing ⚠️
src/Udf/UdfPartition.php 97.22% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main     #121      +/-   ##
============================================
+ Coverage     96.87%   97.42%   +0.55%     
- Complexity      592      888     +296     
============================================
  Files            22       25       +3     
  Lines          1344     1904     +560     
============================================
+ Hits           1302     1855     +553     
- Misses           42       49       +7     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@indy2kro
indy2kro merged commit 43c6eb8 into main Oct 7, 2026
9 checks passed
@indy2kro
indy2kro deleted the feat/improvement-backlog-2026-10-07 branch October 7, 2026 19:31
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