Skip to content

Commit 5e31636

Browse files
authored
fix: preserve timestamps when decompressing folders (#422)
Refs: #190
1 parent 878fa50 commit 5e31636

3 files changed

Lines changed: 27 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
### Fixed
9+
- Fixed the modification of the original timestamp when decompressing folders ([#190])
810

911
## [1.6.1] - 2026-02-14
1012
### Changed

app/src/main/kotlin/org/fossify/filemanager/activities/DecompressActivity.kt

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ class DecompressActivity : SimpleActivity() {
155155
zipInputStream.setPassword(password?.toCharArray())
156156
}
157157
val buffer = ByteArray(1024)
158+
val foldersTimestamp = mutableListOf<Pair<File, LocalFileHeader>>()
158159

159160
zipInputStream.use {
160161
while (true) {
@@ -163,23 +164,28 @@ class DecompressActivity : SimpleActivity() {
163164
val parent = "$destination/$filename"
164165
val newPath = "$parent/${entry.fileName.trimEnd('/')}"
165166

167+
166168
if (!getDoesFilePathExist(parent)) {
167169
if (!createDirectorySync(parent)) {
168170
continue
169171
}
170172
}
171173

172-
if (entry.isDirectory) {
173-
continue
174-
}
175-
176174
val outputFile = File(newPath)
177175

178176
val isVulnerableForZipPathTraversal = !outputFile.canonicalPath.startsWith(parent)
179177
if (isVulnerableForZipPathTraversal) {
180178
continue
181179
}
182180

181+
if (entry.isDirectory) {
182+
if (!outputFile.exists()) {
183+
outputFile.mkdirs()
184+
}
185+
foldersTimestamp.add(Pair(outputFile, entry))
186+
continue
187+
}
188+
183189
val fos = getFileOutputStreamSync(newPath, newPath.getMimeType())
184190
var count: Int
185191
while (true) {
@@ -193,7 +199,9 @@ class DecompressActivity : SimpleActivity() {
193199
fos!!.close()
194200
outputFile.setLastModified(entry)
195201
}
196-
202+
for ((outputFile, entry) in foldersTimestamp.asReversed()) {
203+
outputFile.setLastModified(entry)
204+
}
197205
toast(R.string.decompression_successful)
198206
finish()
199207
}

app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,8 @@ class ItemsAdapter(
720720
paths.forEach { path ->
721721
val zipInputStream =
722722
ZipInputStream(BufferedInputStream(activity.getFileInputStreamSync(path)))
723+
724+
val foldersTimestamp = mutableListOf<Pair<File, LocalFileHeader>>()
723725
zipInputStream.use {
724726
try {
725727
var entry = zipInputStream.nextEntry
@@ -740,26 +742,29 @@ class ItemsAdapter(
740742
if (activity.getIsPathDirectory(path)) {
741743
activity.deleteFolderBg(fileDirItem, false) {
742744
if (it) {
743-
extractEntry(newPath, entry, zipInputStream)
745+
extractEntry(newPath, entry, zipInputStream, foldersTimestamp)
744746
} else {
745747
callback(false)
746748
}
747749
}
748750
} else {
749751
activity.deleteFileBg(fileDirItem, false, false) {
750752
if (it) {
751-
extractEntry(newPath, entry, zipInputStream)
753+
extractEntry(newPath, entry, zipInputStream, foldersTimestamp)
752754
} else {
753755
callback(false)
754756
}
755757
}
756758
}
757759
} else if (!doesPathExist) {
758-
extractEntry(newPath, entry, zipInputStream)
760+
extractEntry(newPath, entry, zipInputStream, foldersTimestamp)
759761
}
760762

761763
entry = zipInputStream.nextEntry
762764
}
765+
for ((dir, header) in foldersTimestamp.asReversed()) {
766+
dir.setLastModified(header)
767+
}
763768
callback(true)
764769
} catch (e: Exception) {
765770
activity.showErrorToast(e)
@@ -772,13 +777,16 @@ class ItemsAdapter(
772777
private fun extractEntry(
773778
newPath: String,
774779
entry: LocalFileHeader,
775-
zipInputStream: ZipInputStream
780+
zipInputStream: ZipInputStream,
781+
foldersTimestamp: MutableList<Pair<File, LocalFileHeader>>
776782
) {
777783
if (entry.isDirectory) {
778784
if (!activity.createDirectorySync(newPath) && !activity.getDoesFilePathExist(newPath)) {
779785
val error =
780786
String.format(activity.getString(R.string.could_not_create_file), newPath)
781787
activity.showErrorToast(error)
788+
} else {
789+
foldersTimestamp.add(Pair(File(newPath), entry))
782790
}
783791
} else {
784792
val fos = activity.getFileOutputStreamSync(newPath, newPath.getMimeType())

0 commit comments

Comments
 (0)