Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preserve Last Modification Date #528

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
e4986d8
Preserve last modified on Dropbox
taglioIsCoding Apr 2, 2024
141a000
Added modifiedDate in DataSource
JustFanta01 Apr 3, 2024
b00ab2e
Merge branch 'feature/preserve-mod-date-main' into feature/preserve-m…
taglioIsCoding Apr 8, 2024
f0a7e5f
Add modified date into gdrive metadata
taglioIsCoding Apr 4, 2024
ccdb472
last modified date for WebDAV and NextCloud
WheelyMcBones Apr 4, 2024
bfeb686
Edited .gitignore
taglioIsCoding Apr 8, 2024
a1edf87
modified date with Optional for GDrive, DropBox, WebDav (not tested)
WheelyMcBones Apr 8, 2024
633fbe4
preserve last modified date on pCloud (not tested!)
JustFanta01 Apr 7, 2024
2bf641c
Modified date with Optional in pCloud
taglioIsCoding Apr 9, 2024
c3715ad
Preserve Last Modified Date on Onedrive
JustFanta01 Apr 3, 2024
c045f7c
last modified date for OneDrive
WheelyMcBones Apr 7, 2024
1d71160
modified chunkedUploadFile with modified date
WheelyMcBones Apr 8, 2024
32c5ef7
modified date with Optional for OneDrive
WheelyMcBones Apr 8, 2024
2098640
Merge branch 'cryptomator:develop' into feature/preserve-mod-date-main
JustFanta01 Apr 9, 2024
7e281a2
Added modifiedDate() in UploadFileTest
JustFanta01 Apr 10, 2024
d1a8d7c
Merge branch 'feature/preserve-mod-date-main' of https://github.com/J…
JustFanta01 Apr 10, 2024
ab9f890
PR requested changes (not tested)
WheelyMcBones Apr 10, 2024
38b4633
Revert changes to the .idea/_ files and the .gitignore
JustFanta01 Apr 18, 2024
cd22b4b
Removed patchAsync request when not useful for Onedrive
JustFanta01 Apr 18, 2024
4dbcdb8
Fixed nullable last modified date for OneDrive
taglioIsCoding Apr 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import com.dropbox.core.v2.files.Metadata
internal object DropboxCloudNodeFactory {

fun from(parent: DropboxFolder, metadata: FileMetadata): DropboxFile {
return DropboxFile(parent, metadata.name, metadata.pathDisplay, metadata.size, metadata.serverModified)
return DropboxFile(parent, metadata.name, metadata.pathDisplay, metadata.size, metadata.clientModified)
}

@JvmStatic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import org.cryptomator.util.file.LruFileCacheUtil.Companion.retrieveFromLruCache
import java.io.File
import java.io.IOException
import java.io.OutputStream
import java.util.Date
import timber.log.Timber

internal class DropboxImpl(cloud: DropboxCloud, context: Context) {
Expand Down Expand Up @@ -167,6 +168,7 @@ internal class DropboxImpl(cloud: DropboxCloud, context: Context) {
client() //
.files() //
.uploadBuilder(file.path) //
.withClientModified(data.modifiedDate(context).orElse(Date())) //
.withMode(writeMode) //
.uploadAndFinish(it)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ internal object OnedriveCloudNodeFactory {
}

private fun lastModified(item: DriveItem): Date? {
return item.lastModifiedDateTime?.let {
return Date.from(it.toInstant())
}
return item.fileSystemInfo?.lastModifiedDateTime?.let { clientDate -> Date.from(clientDate.toInstant()) }
?: item.lastModifiedDateTime?.let { serverDate -> Date.from(serverDate.toInstant()) }
SailReal marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.microsoft.graph.http.GraphServiceException
import com.microsoft.graph.models.DriveItem
import com.microsoft.graph.models.DriveItemCreateUploadSessionParameterSet
import com.microsoft.graph.models.DriveItemUploadableProperties
import com.microsoft.graph.models.FileSystemInfo
SailReal marked this conversation as resolved.
Show resolved Hide resolved
import com.microsoft.graph.models.Folder
import com.microsoft.graph.models.ItemReference
import com.microsoft.graph.options.Option
Expand Down Expand Up @@ -39,6 +40,8 @@ import org.cryptomator.util.file.LruFileCacheUtil.Companion.retrieveFromLruCache
import java.io.File
import java.io.IOException
import java.io.OutputStream
import java.time.OffsetDateTime
import java.time.ZoneId
import java.util.Date
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ExecutionException
Expand Down Expand Up @@ -202,14 +205,21 @@ internal class OnedriveImpl(private val cloud: OnedriveCloud, private val client
}
progressAware.onProgress(Progress.completed(UploadState.upload(file)))
return try {
OnedriveCloudNodeFactory.file(file.parent, result.get(), Date())
val driveItem: DriveItem = result.get()
val lastModifiedDate = getLastModifiedDateTime(driveItem) ?: Date()
OnedriveCloudNodeFactory.file(file.parent, driveItem, lastModifiedDate)
} catch (e: ExecutionException) {
throw FatalBackendException(e)
} catch (e: InterruptedException) {
throw FatalBackendException(e)
}
}

private fun getLastModifiedDateTime(driveItem: DriveItem): Date? {
return driveItem.fileSystemInfo?.lastModifiedDateTime?.let { clientDate -> Date.from(clientDate.toInstant()) }
?: driveItem.lastModifiedDateTime?.let { serverDate -> Date.from(serverDate.toInstant()) }
}

@Throws(NoSuchCloudFileException::class)
private fun uploadFile(file: OnedriveFile, data: DataSource, progressAware: ProgressAware<UploadState>, result: CompletableFuture<DriveItem>, conflictBehaviorOption: Option, size: Long) {
data.open(context)?.use { inputStream ->
Expand All @@ -228,12 +238,26 @@ internal class OnedriveImpl(private val cloud: OnedriveCloud, private val client
.putAsync(CopyStream.toByteArray(it)) //
.whenComplete { driveItem, error ->
run {
if (error == null) {
val modifiedDate = data.modifiedDate(context)
if (error != null) {
result.completeExceptionally(error)
return@whenComplete
}
if (modifiedDate.isPresent) {
patchAsyncLastModifiedDate(parentNodeInfo, driveItem, modifiedDate.get())
.whenComplete { driveItem, error ->
if (error == null) {
progressAware.onProgress(Progress.completed(UploadState.upload(file)))
result.complete(driveItem)
cacheNodeInfo(file, driveItem)
} else {
result.completeExceptionally(error)
}
}
} else { // current date is the default, no need to patch()
progressAware.onProgress(Progress.completed(UploadState.upload(file)))
result.complete(driveItem)
cacheNodeInfo(file, driveItem)
} else {
result.completeExceptionally(error)
}
}
}
Expand All @@ -244,13 +268,32 @@ internal class OnedriveImpl(private val cloud: OnedriveCloud, private val client
} ?: throw FatalBackendException("InputStream shouldn't bee null")
}

private fun patchAsyncLastModifiedDate(parentNodeInfo: OnedriveIdCache.NodeInfo, driveItem: DriveItem, modifiedDate: Date): CompletableFuture<DriveItem> {
val diffItem = DriveItem()
diffItem.fileSystemInfo = FileSystemInfo()
diffItem.fileSystemInfo!!.lastModifiedDateTime = OffsetDateTime.ofInstant(modifiedDate.toInstant(), ZoneId.systemDefault())
return drive(parentNodeInfo.driveId) //
.items(driveItem.id!!) //
.buildRequest() //
.patchAsync(diffItem) //
}

@Throws(IOException::class, NoSuchCloudFileException::class)
private fun chunkedUploadFile(file: OnedriveFile, data: DataSource, progressAware: ProgressAware<UploadState>, result: CompletableFuture<DriveItem>, conflictBehaviorOption: Option, size: Long) {
val parentNodeInfo = requireNodeInfo(file.parent)

val props = DriveItemUploadableProperties()
val modifiedDate = data.modifiedDate(context)

if (modifiedDate.isPresent) {
props.fileSystemInfo = FileSystemInfo()
props.fileSystemInfo!!.lastModifiedDateTime = OffsetDateTime.ofInstant(modifiedDate.get().toInstant(), ZoneId.systemDefault())
}

drive(parentNodeInfo.driveId) //
.items(parentNodeInfo.id) //
.itemWithPath(file.name) //
.createUploadSession(DriveItemCreateUploadSessionParameterSet.newBuilder().withItem(DriveItemUploadableProperties()).build()) //
.createUploadSession(DriveItemCreateUploadSessionParameterSet.newBuilder().withItem(props).build()) //
.buildRequest() //
.post()?.let { uploadSession ->
data.open(context)?.use { inputStream ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ internal class PCloudImpl(private val cloud: PCloud, private val client: ApiClie
}
return try {
client //
.createFile(file.parent.path, file.name, pCloudDataSource, Date(), listener, uploadOptions) //
.createFile(file.parent.path, file.name, pCloudDataSource, data.modifiedDate(context).orElse(Date()), listener, uploadOptions) //
.execute()
} catch (ex: ApiError) {
handleApiError(ex, file.name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.cryptomator.data.cloud.googledrive
import android.content.Context
import com.google.api.client.googleapis.json.GoogleJsonResponseException
import com.google.api.client.http.HttpResponseException
import com.google.api.client.util.DateTime
import com.google.api.services.drive.Drive
import com.google.api.services.drive.model.File
import com.google.api.services.drive.model.Revision
Expand All @@ -25,6 +26,7 @@ import org.cryptomator.util.file.LruFileCacheUtil
import org.cryptomator.util.file.LruFileCacheUtil.Companion.retrieveFromLruCache
import java.io.IOException
import java.io.OutputStream
import java.util.Date
import timber.log.Timber

internal class GoogleDriveImpl(context: Context, googleDriveCloud: GoogleDriveCloud, idCache: GoogleDriveIdCache) {
Expand Down Expand Up @@ -203,6 +205,7 @@ internal class GoogleDriveImpl(context: Context, googleDriveCloud: GoogleDriveCl
val metadata = File()
metadata.name = file.name
progressAware.onProgress(Progress.started(UploadState.upload(file)))
metadata.setModifiedTime(DateTime(data.modifiedDate(context).orElse(Date())))
val uploadedFile = if (file.driveId != null && replace) {
updateFile(file, data, progressAware, size, metadata)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ abstract class CryptoImplDecorator(
progressAware.onProgress(Progress.progress(UploadState.encryption(cryptoFile)).between(0).and(ciphertextSize).withValue(encrypted))
}
encryptingWritableByteChannel.close()
data.modifiedDate(context).ifPresent { encryptedTmpFile.setLastModified(it.time) }
SailReal marked this conversation as resolved.
Show resolved Hide resolved
progressAware.onProgress(Progress.completed(UploadState.encryption(cryptoFile)))
return writeFromTmpFile(data, cryptoFile, encryptedTmpFile, progressAware, replace)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ open class CryptoImplVaultFormat7 : CryptoImplDecorator {
progressAware.onProgress(Progress.progress(UploadState.encryption(cloudFile)).between(0).and(ciphertextSize).withValue(encrypted))
}
encryptingWritableByteChannel.close()
data.modifiedDate(context).ifPresent { encryptedTmpFile.setLastModified(it.time) }
progressAware.onProgress(Progress.completed(UploadState.encryption(cloudFile)))
val targetFile = targetFile(cryptoFile, cloudFile, replace)
return file(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import org.cryptomator.domain.usecases.cloud.Progress
import org.cryptomator.domain.usecases.cloud.UploadState
import java.io.IOException
import java.io.OutputStream
import java.util.Date
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull

internal class WebDavImpl(private val cloud: WebDavCloud, private val connectionHandler: ConnectionHandlerHandlerImpl, private val context: Context) {
Expand Down Expand Up @@ -133,7 +134,7 @@ internal class WebDavImpl(private val cloud: WebDavCloud, private val connection
)
}
}.use {
connectionHandler.writeFile(absoluteUriFrom(uploadFile.path), it)
connectionHandler.writeFile(absoluteUriFrom(uploadFile.path), it, data.modifiedDate(context).orElse(Date()))
}
} ?: throw FatalBackendException("InputStream shouldn't bee null")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.cryptomator.data.cloud.webdav.WebDavNode
import org.cryptomator.domain.CloudFolder
import org.cryptomator.domain.exception.BackendException
import java.io.InputStream
import java.util.Date
import javax.inject.Inject

class ConnectionHandlerHandlerImpl @Inject internal constructor(httpClient: WebDavCompatibleHttpClient) {
Expand All @@ -27,8 +28,8 @@ class ConnectionHandlerHandlerImpl @Inject internal constructor(httpClient: WebD
}

@Throws(BackendException::class)
fun writeFile(url: String, inputStream: InputStream) {
webDavClient.writeFile(url, inputStream)
fun writeFile(url: String, inputStream: InputStream, modifiedDate: Date) {
webDavClient.writeFile(url, inputStream, modifiedDate)
}

@Throws(BackendException::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import java.io.IOException
import java.io.InputStream
import java.net.HttpURLConnection
import java.util.Collections
import java.util.Date
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
Expand Down Expand Up @@ -150,8 +151,9 @@ internal class WebDavClient(private val httpClient: WebDavCompatibleHttpClient)
}

@Throws(BackendException::class)
fun writeFile(url: String, inputStream: InputStream) {
fun writeFile(url: String, inputStream: InputStream, modifiedDate: Date) {
val builder = Request.Builder() //
.addHeader("X-OC-Mtime", modifiedDate.toInstant().toEpochMilli().div(1000).toString()) //
.put(InputStreamSourceBasedRequestBody.from(inputStream)) //
.url(url)
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.cryptomator.domain.usecases.cloud

import android.content.Context
import org.cryptomator.util.Optional
import java.io.ByteArrayInputStream
import java.io.IOException
import java.io.InputStream
import java.util.Date

class ByteArrayDataSource private constructor(private val bytes: ByteArray) : DataSource {

Expand All @@ -25,6 +27,10 @@ class ByteArrayDataSource private constructor(private val bytes: ByteArray) : Da
// do nothing because ByteArrayInputStream need no close
}

override fun modifiedDate(context: Context): Optional<Date> {
return Optional.empty()
}

companion object {

@JvmStatic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package org.cryptomator.domain.usecases.cloud

import android.content.Context
import org.cryptomator.domain.exception.CancellationException
import org.cryptomator.util.Optional
import java.io.IOException
import java.io.InputStream
import java.util.Date

class CancelAwareDataSource private constructor(private val delegate: DataSource, private val cancelled: Flag) : DataSource {

Expand Down Expand Up @@ -31,6 +33,13 @@ class CancelAwareDataSource private constructor(private val delegate: DataSource
delegate.close()
}

override fun modifiedDate(context: Context): Optional<Date> {
if (cancelled.get()) {
throw CancellationException()
}
return delegate.modifiedDate(context)
}

companion object {

@JvmStatic
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package org.cryptomator.domain.usecases.cloud

import android.content.Context
import org.cryptomator.util.Optional
import java.io.Closeable
import java.io.IOException
import java.io.InputStream
import java.io.Serializable
import java.util.Date

SailReal marked this conversation as resolved.
Show resolved Hide resolved
interface DataSource : Serializable, Closeable {

Expand All @@ -15,4 +17,6 @@ interface DataSource : Serializable, Closeable {

fun decorate(delegate: DataSource): DataSource

fun modifiedDate(context: Context): Optional<Date>

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package org.cryptomator.domain.usecases.cloud

import android.content.Context
import org.cryptomator.util.Optional
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.io.InputStream
import java.util.Date

class FileBasedDataSource private constructor(private val file: File) : DataSource {

Expand All @@ -26,6 +28,10 @@ class FileBasedDataSource private constructor(private val file: File) : DataSour
// Do nothing
}

override fun modifiedDate(context: Context): Optional<Date> {
return Optional.of(Date(file.lastModified()))
}

companion object {

@JvmStatic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ private File copyDataToFile(DataSource dataSource) {
InputStream in = CancelAwareDataSource.wrap(dataSource, cancelledFlag).open(context);
OutputStream out = new FileOutputStream(target);
copy(in, out);
dataSource.modifiedDate(context).ifPresent(value -> target.setLastModified(value.getTime()));
return target;
} catch (IOException e) {
throw new FatalBackendException(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.cryptomator.domain.CloudNode
import org.cryptomator.domain.exception.BackendException
import org.cryptomator.domain.repository.CloudContentRepository
import org.cryptomator.domain.usecases.ProgressAware
import org.cryptomator.util.Optional
import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert
import org.junit.jupiter.params.ParameterizedTest
Expand All @@ -21,6 +22,7 @@ import java.io.ByteArrayInputStream
import java.io.IOException
import java.io.InputStream
import java.util.Arrays
import java.util.Date

class UploadFileTest {

Expand Down Expand Up @@ -105,6 +107,10 @@ class UploadFileTest {
return delegate
}

override fun modifiedDate(context: Context): Optional<Date> {
return Optional.of(Date())
}

@Throws(IOException::class)
override fun close() {
// do nothing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import android.content.Context
import android.net.Uri
import org.cryptomator.domain.usecases.cloud.DataSource
import org.cryptomator.presentation.util.ContentResolverUtil
import org.cryptomator.util.Optional
import java.io.IOException
import java.io.InputStream
import java.util.Date

class UriBasedDataSource private constructor(private val uri: Uri) : DataSource {

Expand All @@ -27,6 +29,10 @@ class UriBasedDataSource private constructor(private val uri: Uri) : DataSource
// do nothing
}

override fun modifiedDate(context: Context): Optional<Date> {
return Optional.ofNullable(ContentResolverUtil(context).fileModifiedDate(uri))
}

companion object {

@JvmStatic
Expand Down
Loading