Skip to content

Filesystem 48490: Unzip keeps the ZIP-file open after extracting - #12204

Merged
chfsx merged 1 commit into
ILIAS-eLearning:release_10from
srsolutionsag:fix/48490/10
Oct 13, 2026
Merged

chfsx merged 1 commit into
ILIAS-eLearning:release_10from
srsolutionsag:fix/48490/10

Conversation

@chfsx

@chfsx chfsx commented Oct 13, 2026

Copy link
Copy Markdown
Member

This PR fixes the cause of https://mantis.ilias.de/view.php?id=48490 in the Filesystem component and replaces #12197.

Unzip kept the passed stream (usually Streams::ofResource(fopen(...))) and the ZipArchive open for its whole lifetime. Consumers which delete the ZIP-file or its directory in the same scope after extract() (e.g. the test import in ilObjTestGUI::importFile()) fail on file systems like NFS, where open files can not be removed. Two file handles on the ZIP-file stayed open after extract() and were only released when the Unzip object was destroyed.

Changes in Unzip:

  • only the path of the passed stream is kept, so a stream created just for the Unzip is closed immediately. Streams held by the consumer are not closed.
  • extract() releases the archive in any case (also for unreadable or rejected archives), in FLAT_STRUCTURE mode every entry stream is closed after writing it.
  • new close() for consumers which only read paths or streams.
  • the archive is reopened if it is accessed after it has been closed (e.g. ZipAdapter calls getFiles() after extract()).
  • the result of ZipArchive::open() is checked instead of relying on count() throwing for unopened archives.

This fixes the issue for all consumers of Unzip, so no changes in the Test component are needed.

Tests: UnzipTest now counts the open file handles of the process and ensures that none are left after extract() (for all directory handlings, rejected archives and unreadable files), that the ZIP-file and its directory can be deleted while the Unzip is still in scope, that consumer streams stay open, that the archive is reopened on access and that close() is idempotent. The new handle tests fail without the fix.

Unzip kept the passed stream and the ZipArchive open for its whole
lifetime. Consumers which delete the ZIP-file or its directory in the
same scope after extract() (e.g. the test import) failed on file systems
like NFS, where open files can not be removed.

- only the path of the passed stream is kept, so a stream created just
  for the Unzip is closed immediately
- extract() releases the archive in any case
- new close() for consumers which only read paths or streams
- the archive is reopened if it is accessed after it has been closed
- the result of ZipArchive::open() is checked
@chfsx chfsx self-assigned this Oct 13, 2026
@chfsx chfsx added bugfix php Pull requests that update Php code labels Oct 13, 2026
@chfsx
chfsx marked this pull request as ready for review October 13, 2026 14:24
@chfsx
chfsx merged commit 2f6ed0c into ILIAS-eLearning:release_10 Oct 13, 2026
2 checks passed
@chfsx
chfsx deleted the fix/48490/10 branch October 13, 2026 14:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix php Pull requests that update Php code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant