https://bugs.kde.org/show_bug.cgi?id=524702
Bug ID: 524702
Summary: Regression: Ark commit 189f1f4e causes Drag-and-drop
extraction with the libarchive plugin to silently omit
empty directories
Classification: Applications
Product: ark
Version First 26.03.80
Reported In:
Platform: Fedora RPMs
OS: Linux
Status: REPORTED
Severity: major
Priority: NOR
Component: plugins
Assignee: [email protected]
Reporter: [email protected]
CC: [email protected]
Target Milestone: ---
Created attachment 195436
--> https://bugs.kde.org/attachment.cgi?id=195436&action=edit
picture of archive contents vs. extraction result
Ark silently omits empty directories when a directory tree is dragged from the
Ark GUI and dropped into a folder in Dolphin. This is a regression: `25.12.3`
works, while `26.04.2`, `26.04.3`, and `26.08.0` reproduce the problem.
Normal full-archive extraction is not affected. The same archive extracts
correctly using Ark's regular Extract/Extract All operation, `ark --batch`,
`bsdtar`, or `tar`.
# Steps To Reproduce
1. Create a small archive containing both an empty and a non-empty directory:
```bash
rm -rf /tmp/ark-dnd-source /tmp/ark-dnd-target
mkdir -p /tmp/ark-dnd-source/root/empty
mkdir -p /tmp/ark-dnd-source/root/nonempty
printf 'test\n' > /tmp/ark-dnd-source/root/nonempty/file.txt
tar -C /tmp/ark-dnd-source -czf /tmp/ark-dnd-empty-dir.tar.gz root
mkdir -p /tmp/ark-dnd-target
```
2. Open `/tmp/ark-dnd-empty-dir.tar.gz` in Ark.
3. Drag the `root` directory from Ark's archive view and drop it into
`/tmp/ark-dnd-target` in Dolphin.
4. Inspect the extracted tree:
```bash
find /tmp/ark-dnd-target -print | sort
```
# Observed Result
`root/nonempty/file.txt` is extracted, and its parent directories are
implicitly recreated, but `root/empty` is missing.
# Expected Result
The complete selected tree is extracted, including `root/empty`.
# Regression Range
- Last tested working version: Ark/ark-libs `25.12.3`
- First tested broken version: Ark/ark-libs `26.04.2`
- Also broken: `26.04.3` and `26.08.0`
- The regression is introduced by commit
`189f1f4e411086d996d4e581c425a380d160b899` (included beginning with the
`26.03.80` tag):
<https://invent.kde.org/utilities/ark/-/commit/189f1f4e411086d996d4e581c425a380d160b899>
# Technical Analysis
Commit `189f1f4e411086d996d4e581c425a380d160b899` correctly normalizes
libarchive directory entry names by removing trailing `/` characters before
checking for existing destination files. However, partial extraction still
builds `fullPaths` and `remainingFiles` with
`ReadOnlyArchiveInterface::entryFullPaths()` using its default
`WithTrailingSlash` format.
During drag-and-drop extraction Ark supplies an explicit selected-entry list. A
selected directory is therefore stored as `root/empty/`, while the
corresponding libarchive entry is normalized to `root/empty`. The membership
test fails and Ark skips the directory entry. Parent directories for regular
files are recreated as a side effect, which hides the problem for every
directory except genuinely empty ones.
Full extraction passes an empty selected-entry list and uses the `extractAll`
path, so it bypasses the mismatched membership test and works correctly.
# Proposed Fix
Normalize the two explicit selected-entry lists with the same representation
used for libarchive entries:
```cpp
const QStringList fullPaths = entryFullPaths(files, NoTrailingSlash);
QStringList remainingFiles = entryFullPaths(files, NoTrailingSlash);
```
The attached patch also adds a regression test using the existing
`empty_folders.tar.gz` fixture and drag-and-drop extraction options:
```
>From 4cadf90043fbbe2c5bfc48355e2405b18f337811 Mon Sep 17 00:00:00 2001
From: GloriousEggroll <[email protected]>
Date: Mon, 24 Aug 2026 06:04:05 -0600
Subject: [PATCH] libarchive: Preserve empty directories during partial
extraction
Commit 189f1f4e411086d996d4e581c425a380d160b899 normalized libarchive directory
entry names by removing trailing slashes. The explicit selected-entry lists
retained their trailing slashes, so directory entries no longer matched during
partial and drag-and-drop extraction. Non-empty parent directories were
recreated while extracting files, but empty directories were silently omitted.
Normalize both selected-entry lists to the same no-trailing-slash
representation and add coverage for drag-and-drop extraction of empty
directories.
Fixes: 189f1f4e411086d996d4e581c425a380d160b899
---
autotests/kerfuffle/extracttest.cpp | 13 +++++++++++++
plugins/libarchive/libarchiveplugin.cpp | 4 ++--
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/autotests/kerfuffle/extracttest.cpp
b/autotests/kerfuffle/extracttest.cpp
index 8f9774fd..10721326 100644
--- a/autotests/kerfuffle/extracttest.cpp
+++ b/autotests/kerfuffle/extracttest.cpp
@@ -181,6 +181,19 @@ void ExtractTest::testExtraction_data()
archivePath = QFINDTESTDATA("data/empty_folders.tar.gz");
setupRow("tar with empty folders", archivePath, QList<Archive::Entry *>(),
optionsPreservePaths, 5);
+ archivePath = QFINDTESTDATA("data/empty_folders.tar.gz");
+ setupRow("extract selected empty folders from a tar.gz, drag-and-drop",
+ archivePath,
+ QList<Archive::Entry *>{
+ new Archive::Entry(this, QStringLiteral("A/"), QString()),
+ new Archive::Entry(this, QStringLiteral("A/B/"), QString()),
+ new Archive::Entry(this, QStringLiteral("A/B/test.txt"),
QString()),
+ new Archive::Entry(this, QStringLiteral("A/B/C/"),
QString()),
+ new Archive::Entry(this, QStringLiteral("A/B1/"), QString()),
+ },
+ dragAndDropOptions,
+ 5);
+
archivePath = QFINDTESTDATA("data/simplearchive.tar.bz2");
setupRow("extract selected entries from a bzip2-compressed tarball without
path",
archivePath,
diff --git a/plugins/libarchive/libarchiveplugin.cpp
b/plugins/libarchive/libarchiveplugin.cpp
index d625ea51..26e59bd7 100644
--- a/plugins/libarchive/libarchiveplugin.cpp
+++ b/plugins/libarchive/libarchiveplugin.cpp
@@ -293,8 +293,8 @@ bool LibarchivePlugin::extractFiles(const
QList<Archive::Entry *> &files, const
QString fileBeingRenamed;
// To avoid traversing the entire archive when extracting a limited set of
// entries, we maintain a list of remaining entries and stop when it's
empty.
- const QStringList fullPaths = entryFullPaths(files);
- QStringList remainingFiles = entryFullPaths(files);
+ const QStringList fullPaths = entryFullPaths(files, NoTrailingSlash);
+ QStringList remainingFiles = entryFullPaths(files, NoTrailingSlash);
// Iterate through all entries in archive.
while (!QThread::currentThread()->isInterruptionRequested() &&
(archive_read_next_header(m_archiveReader.data(), &entry) == ARCHIVE_OK)) {
--
2.55.0
```
# System Information
- OS: Nobara Linux 44 KDE Plasma Edition
- Working Ark version currently installed: `25.12.3-1.fc44`
- Broken Ark versions tested: `26.04.2-1.fc43`, `26.04.3-1.fc44`,
`26.08.0-1.fc44`
- libarchive: `3.8.7-1.fc44`
- KDE Plasma: `6.7.4-1.fc44`
- KDE Frameworks KArchive: `6.29.0-1.fc44`
- Qt: `6.11.1-1.fc44`
Extra:
I changed the severity to major as it effects basic user experience and can
have severe trickle-down effects.
For example users manually installing custom proton versions for Steam will
unknowingly end up with broken proton extractions and subsequently broken game
launches.
Specifically, the default_pfx folder in proton builds can break because it
contains several empty directories that games/applications expect to exist in
the prefix. Since proton copies default_pfx instead of using wineboot, those
folders never get re-created:
--
You are receiving this mail because:
You are watching all bug changes.