From dfd79953c5dea5f09724ba03dc89e4003d006831 Mon Sep 17 00:00:00 2001 From: Jalila BAALI Date: Fri, 3 Apr 2026 20:57:36 +0200 Subject: [PATCH 1/2] Fix: Decompress folder retain their original timestamps --- .../filemanager/activities/DecompressActivity.kt | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/kotlin/org/fossify/filemanager/activities/DecompressActivity.kt b/app/src/main/kotlin/org/fossify/filemanager/activities/DecompressActivity.kt index 39d03354..a55fe7e6 100644 --- a/app/src/main/kotlin/org/fossify/filemanager/activities/DecompressActivity.kt +++ b/app/src/main/kotlin/org/fossify/filemanager/activities/DecompressActivity.kt @@ -155,6 +155,7 @@ class DecompressActivity : SimpleActivity() { zipInputStream.setPassword(password?.toCharArray()) } val buffer = ByteArray(1024) + val foldersTimestamp = mutableListOf>() zipInputStream.use { while (true) { @@ -162,6 +163,7 @@ class DecompressActivity : SimpleActivity() { val filename = filename.substringBeforeLast(".") val parent = "$destination/$filename" val newPath = "$parent/${entry.fileName.trimEnd('/')}" + val outputFile = File(newPath) if (!getDoesFilePathExist(parent)) { if (!createDirectorySync(parent)) { @@ -170,10 +172,14 @@ class DecompressActivity : SimpleActivity() { } if (entry.isDirectory) { + if (!getDoesFilePathExist(newPath)) { + createDirectorySync(newPath) + } + + foldersTimestamp.add(Pair(outputFile,entry)) continue - } - val outputFile = File(newPath) + } val isVulnerableForZipPathTraversal = !outputFile.canonicalPath.startsWith(parent) if (isVulnerableForZipPathTraversal) { @@ -193,7 +199,9 @@ class DecompressActivity : SimpleActivity() { fos!!.close() outputFile.setLastModified(entry) } - + for ((folder,header) in foldersTimestamp){ + folder.setLastModified((header)) + } toast(R.string.decompression_successful) finish() } From 4494f15a477a1fa87c8a1f39614c7d009b814ded Mon Sep 17 00:00:00 2001 From: Jalila BAALI Date: Thu, 16 Apr 2026 00:43:42 +0200 Subject: [PATCH 2/2] Fix: Preserve folder timestamps when decompressing --- .../filemanager/activities/DecompressActivity.kt | 16 ++++++++-------- .../fossify/filemanager/adapters/ItemsAdapter.kt | 16 ++++++++++++---- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/app/src/main/kotlin/org/fossify/filemanager/activities/DecompressActivity.kt b/app/src/main/kotlin/org/fossify/filemanager/activities/DecompressActivity.kt index a55fe7e6..dfb108ad 100644 --- a/app/src/main/kotlin/org/fossify/filemanager/activities/DecompressActivity.kt +++ b/app/src/main/kotlin/org/fossify/filemanager/activities/DecompressActivity.kt @@ -163,7 +163,7 @@ class DecompressActivity : SimpleActivity() { val filename = filename.substringBeforeLast(".") val parent = "$destination/$filename" val newPath = "$parent/${entry.fileName.trimEnd('/')}" - val outputFile = File(newPath) + if (!getDoesFilePathExist(parent)) { if (!createDirectorySync(parent)) { @@ -172,14 +172,14 @@ class DecompressActivity : SimpleActivity() { } if (entry.isDirectory) { - if (!getDoesFilePathExist(newPath)) { - createDirectorySync(newPath) + val dir = File(newPath) + if (!dir.exists()) { + dir.mkdirs() } - - foldersTimestamp.add(Pair(outputFile,entry)) + foldersTimestamp.add(Pair(dir, entry)) continue - } + val outputFile = File(newPath) val isVulnerableForZipPathTraversal = !outputFile.canonicalPath.startsWith(parent) if (isVulnerableForZipPathTraversal) { @@ -199,8 +199,8 @@ class DecompressActivity : SimpleActivity() { fos!!.close() outputFile.setLastModified(entry) } - for ((folder,header) in foldersTimestamp){ - folder.setLastModified((header)) + for ((dir, entry) in foldersTimestamp.asReversed()) { + dir.setLastModified(entry) } toast(R.string.decompression_successful) finish() diff --git a/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt b/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt index bea52946..90b471f4 100644 --- a/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt +++ b/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt @@ -720,6 +720,8 @@ class ItemsAdapter( paths.forEach { path -> val zipInputStream = ZipInputStream(BufferedInputStream(activity.getFileInputStreamSync(path))) + + val foldersTimestamp = mutableListOf>() zipInputStream.use { try { var entry = zipInputStream.nextEntry @@ -740,7 +742,7 @@ class ItemsAdapter( if (activity.getIsPathDirectory(path)) { activity.deleteFolderBg(fileDirItem, false) { if (it) { - extractEntry(newPath, entry, zipInputStream) + extractEntry(newPath, entry, zipInputStream, foldersTimestamp) } else { callback(false) } @@ -748,18 +750,21 @@ class ItemsAdapter( } else { activity.deleteFileBg(fileDirItem, false, false) { if (it) { - extractEntry(newPath, entry, zipInputStream) + extractEntry(newPath, entry, zipInputStream, foldersTimestamp) } else { callback(false) } } } } else if (!doesPathExist) { - extractEntry(newPath, entry, zipInputStream) + extractEntry(newPath, entry, zipInputStream, foldersTimestamp) } entry = zipInputStream.nextEntry } + for ((dir, header) in foldersTimestamp.asReversed()) { + dir.setLastModified(header) + } callback(true) } catch (e: Exception) { activity.showErrorToast(e) @@ -772,13 +777,16 @@ class ItemsAdapter( private fun extractEntry( newPath: String, entry: LocalFileHeader, - zipInputStream: ZipInputStream + zipInputStream: ZipInputStream, + foldersTimestamp: MutableList> ) { if (entry.isDirectory) { if (!activity.createDirectorySync(newPath) && !activity.getDoesFilePathExist(newPath)) { val error = String.format(activity.getString(R.string.could_not_create_file), newPath) activity.showErrorToast(error) + } else { + foldersTimestamp.add(Pair(File(newPath), entry)) } } else { val fos = activity.getFileOutputStreamSync(newPath, newPath.getMimeType())