From eee016c6432b72df56921f4aa40905f3189f1fc2 Mon Sep 17 00:00:00 2001 From: hstyi Date: Tue, 1 Jul 2025 10:39:08 +0800 Subject: [PATCH] chore: supports retaining file modification date --- .../app/termora/transfer/FileTransfer.kt | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/app/termora/transfer/FileTransfer.kt b/src/main/kotlin/app/termora/transfer/FileTransfer.kt index be96843..9ce679c 100644 --- a/src/main/kotlin/app/termora/transfer/FileTransfer.kt +++ b/src/main/kotlin/app/termora/transfer/FileTransfer.kt @@ -1,12 +1,19 @@ package app.termora.transfer +import app.termora.database.DatabaseManager import org.apache.commons.io.IOUtils +import org.apache.sshd.sftp.client.fs.SftpFileSystem +import org.apache.sshd.sftp.common.SftpConstants +import org.slf4j.LoggerFactory import java.io.Closeable import java.io.InputStream import java.io.OutputStream +import java.nio.file.Files import java.nio.file.Path import java.nio.file.StandardOpenOption +import java.nio.file.attribute.BasicFileAttributeView import java.util.concurrent.atomic.AtomicBoolean +import kotlin.io.path.getLastModifiedTime import kotlin.io.path.inputStream import kotlin.io.path.outputStream @@ -15,10 +22,13 @@ class FileTransfer( private val action: TransferAction, priority: Transfer.Priority = Transfer.Priority.Normal, ) : AbstractTransfer(parentId, source, target, false, priority), Closeable { + companion object { + private val log = LoggerFactory.getLogger(FileTransfer::class.java) + } private lateinit var input: InputStream private lateinit var output: OutputStream - + private val isPreserveModificationTime get() = DatabaseManager.getInstance().sftp.preserveModificationTime private val closed = AtomicBoolean(false) override suspend fun transfer(bufferSize: Int): Long { @@ -31,7 +41,7 @@ class FileTransfer( if (::output.isInitialized.not()) { output = if (action == TransferAction.Overwrite) { - target().outputStream(StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING) + target().outputStream() } else { target().outputStream(StandardOpenOption.WRITE, StandardOpenOption.APPEND) } @@ -40,6 +50,7 @@ class FileTransfer( val buffer = ByteArray(bufferSize) val len = input.read(buffer) if (len <= 0) return 0 + output.write(buffer, 0, len) return len.toLong() } @@ -61,6 +72,24 @@ class FileTransfer( if (::output.isInitialized) { IOUtils.closeQuietly(output) } + + if (isPreserveModificationTime) { + runCatching { + val time = source().getLastModifiedTime() + val fs = target().fileSystem + // SFTP 比较特殊 + if (fs is SftpFileSystem && fs.version == SftpConstants.SFTP_V3) { + val view = Files.getFileAttributeView(target(), BasicFileAttributeView::class.java) + view.setTimes(time, time, null) + } else { + Files.setLastModifiedTime(target(), time) + } + }.onFailure { + if (log.isWarnEnabled) { + log.error(it.message, it) + } + } + } } }