Skip to content
Merged
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Fixed
- Fixed the modification of the original timestamp when decompressing folders ([#190])

## [1.6.1] - 2026-02-14
### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ class DecompressActivity : SimpleActivity() {
zipInputStream.setPassword(password?.toCharArray())
}
val buffer = ByteArray(1024)
val foldersTimestamp = mutableListOf<Pair<File, LocalFileHeader>>()

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


if (!getDoesFilePathExist(parent)) {
if (!createDirectorySync(parent)) {
continue
}
}

if (entry.isDirectory) {
continue
}

val outputFile = File(newPath)

val isVulnerableForZipPathTraversal = !outputFile.canonicalPath.startsWith(parent)
if (isVulnerableForZipPathTraversal) {
continue
}

if (entry.isDirectory) {
if (!outputFile.exists()) {
outputFile.mkdirs()
}
foldersTimestamp.add(Pair(outputFile, entry))
continue
}

val fos = getFileOutputStreamSync(newPath, newPath.getMimeType())
var count: Int
while (true) {
Expand All @@ -193,7 +199,9 @@ class DecompressActivity : SimpleActivity() {
fos!!.close()
outputFile.setLastModified(entry)
}

for ((outputFile, entry) in foldersTimestamp.asReversed()) {
outputFile.setLastModified(entry)
}
toast(R.string.decompression_successful)
finish()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,8 @@ class ItemsAdapter(
paths.forEach { path ->
val zipInputStream =
ZipInputStream(BufferedInputStream(activity.getFileInputStreamSync(path)))

val foldersTimestamp = mutableListOf<Pair<File, LocalFileHeader>>()
zipInputStream.use {
try {
var entry = zipInputStream.nextEntry
Expand All @@ -740,26 +742,29 @@ class ItemsAdapter(
if (activity.getIsPathDirectory(path)) {
activity.deleteFolderBg(fileDirItem, false) {
if (it) {
extractEntry(newPath, entry, zipInputStream)
extractEntry(newPath, entry, zipInputStream, foldersTimestamp)
} else {
callback(false)
}
}
} 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)
Expand All @@ -772,13 +777,16 @@ class ItemsAdapter(
private fun extractEntry(
newPath: String,
entry: LocalFileHeader,
zipInputStream: ZipInputStream
zipInputStream: ZipInputStream,
foldersTimestamp: MutableList<Pair<File, LocalFileHeader>>
) {
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())
Expand Down
Loading