-
Notifications
You must be signed in to change notification settings - Fork 403
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bug: #191
- Loading branch information
Showing
29 changed files
with
1,970 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
app/src/main/java/at/bitfire/dav4jvm/DavResourceAccessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* | ||
* Copyright (c) 2024 Hai Zhang <dreaming.in.code.zh@gmail.com> | ||
* All Rights Reserved. | ||
*/ | ||
|
||
package at.bitfire.dav4jvm; | ||
|
||
import java.io.IOException; | ||
|
||
import androidx.annotation.NonNull; | ||
import at.bitfire.dav4jvm.exception.DavException; | ||
import at.bitfire.dav4jvm.exception.HttpException; | ||
import kotlin.jvm.functions.Function0; | ||
import okhttp3.Response; | ||
|
||
public class DavResourceAccessor { | ||
private DavResourceAccessor() {} | ||
|
||
public static void checkStatus(@NonNull DavResource davResource, @NonNull Response response) | ||
throws HttpException { | ||
davResource.checkStatus(response); | ||
} | ||
|
||
public static Response followRedirects(@NonNull DavResource davResource, | ||
@NonNull Function0<Response> sendRequest) throws DavException, IOException { | ||
return davResource.followRedirects$build(sendRequest); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
app/src/main/java/me/zhanghai/android/files/provider/webdav/DavExceptionExtensions.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package me.zhanghai.android.files.provider.webdav | ||
|
||
import at.bitfire.dav4jvm.exception.ConflictException | ||
import at.bitfire.dav4jvm.exception.DavException | ||
import at.bitfire.dav4jvm.exception.ForbiddenException | ||
import at.bitfire.dav4jvm.exception.NotFoundException | ||
import at.bitfire.dav4jvm.exception.UnauthorizedException | ||
import java8.nio.file.AccessDeniedException | ||
import java8.nio.file.FileAlreadyExistsException | ||
import java8.nio.file.FileSystemException | ||
import java8.nio.file.NoSuchFileException | ||
import me.zhanghai.android.files.provider.webdav.client.DavIOException | ||
|
||
fun DavException.toFileSystemException( | ||
file: String?, | ||
other: String? = null | ||
): FileSystemException { | ||
return when (this) { | ||
is DavIOException -> | ||
return FileSystemException(file, other, message).apply { initCause(cause) } | ||
is UnauthorizedException, is ForbiddenException -> | ||
AccessDeniedException(file, other, message) | ||
is NotFoundException -> NoSuchFileException(file, other, message) | ||
is ConflictException -> FileAlreadyExistsException(file, other, message) | ||
else -> FileSystemException(file, other, message) | ||
}.apply { initCause(this@toFileSystemException) } | ||
} |
21 changes: 21 additions & 0 deletions
21
app/src/main/java/me/zhanghai/android/files/provider/webdav/OpenOptionsWebDavExtensions.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/* | ||
* Copyright (c) 2024 Hai Zhang <dreaming.in.code.zh@gmail.com> | ||
* All Rights Reserved. | ||
*/ | ||
|
||
package me.zhanghai.android.files.provider.webdav | ||
|
||
import java8.nio.file.StandardOpenOption | ||
import me.zhanghai.android.files.provider.common.OpenOptions | ||
|
||
internal fun OpenOptions.checkForWebDav() { | ||
if (deleteOnClose) { | ||
throw UnsupportedOperationException(StandardOpenOption.DELETE_ON_CLOSE.toString()) | ||
} | ||
if (sync) { | ||
throw UnsupportedOperationException(StandardOpenOption.SYNC.toString()) | ||
} | ||
if (dsync) { | ||
throw UnsupportedOperationException(StandardOpenOption.DSYNC.toString()) | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
app/src/main/java/me/zhanghai/android/files/provider/webdav/PathWebDavExtensions.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/* | ||
* Copyright (c) 2024 Hai Zhang <dreaming.in.code.zh@gmail.com> | ||
* All Rights Reserved. | ||
*/ | ||
|
||
package me.zhanghai.android.files.provider.webdav | ||
|
||
import java8.nio.file.Path | ||
import me.zhanghai.android.files.provider.webdav.client.Authority | ||
|
||
fun Authority.createWebDavRootPath(): Path = | ||
WebDavFileSystemProvider.getOrNewFileSystem(this).rootDirectory |
185 changes: 185 additions & 0 deletions
185
app/src/main/java/me/zhanghai/android/files/provider/webdav/WebDavCopyMove.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
/* | ||
* Copyright (c) 2024 Hai Zhang <dreaming.in.code.zh@gmail.com> | ||
* All Rights Reserved. | ||
*/ | ||
|
||
package me.zhanghai.android.files.provider.webdav | ||
|
||
import at.bitfire.dav4jvm.exception.DavException | ||
import java8.nio.file.FileAlreadyExistsException | ||
import java8.nio.file.NoSuchFileException | ||
import java8.nio.file.StandardCopyOption | ||
import me.zhanghai.android.files.provider.common.CopyOptions | ||
import me.zhanghai.android.files.provider.common.copyTo | ||
import me.zhanghai.android.files.provider.webdav.client.Client | ||
import me.zhanghai.android.files.provider.webdav.client.isDirectory | ||
import me.zhanghai.android.files.provider.webdav.client.isSymbolicLink | ||
import me.zhanghai.android.files.provider.webdav.client.lastModifiedTime | ||
import me.zhanghai.android.files.provider.webdav.client.size | ||
import java.io.IOException | ||
|
||
internal object WebDavCopyMove { | ||
@Throws(IOException::class) | ||
fun copy(source: WebDavPath, target: WebDavPath, copyOptions: CopyOptions) { | ||
if (copyOptions.atomicMove) { | ||
throw UnsupportedOperationException(StandardCopyOption.ATOMIC_MOVE.toString()) | ||
} | ||
val sourceResponse = try { | ||
Client.findProperties(source, copyOptions.noFollowLinks) | ||
} catch (e: DavException) { | ||
throw e.toFileSystemException(source.toString()) | ||
} | ||
val targetFile = try { | ||
Client.findPropertiesOrNull(target, true) | ||
} catch (e: DavException) { | ||
throw e.toFileSystemException(target.toString()) | ||
} | ||
val sourceSize = sourceResponse.size | ||
if (targetFile != null) { | ||
if (source == target) { | ||
copyOptions.progressListener?.invoke(sourceSize) | ||
return | ||
} | ||
if (!copyOptions.replaceExisting) { | ||
throw FileAlreadyExistsException(source.toString(), target.toString(), null) | ||
} | ||
try { | ||
Client.delete(target) | ||
} catch (e: DavException) { | ||
throw e.toFileSystemException(target.toString()) | ||
} | ||
} | ||
when { | ||
sourceResponse.isDirectory -> { | ||
try { | ||
Client.makeCollection(target) | ||
} catch (e: DavException) { | ||
throw e.toFileSystemException(target.toString()) | ||
} | ||
copyOptions.progressListener?.invoke(sourceSize) | ||
} | ||
sourceResponse.isSymbolicLink -> | ||
throw UnsupportedOperationException("Cannot copy symbolic links") | ||
else -> { | ||
val sourceInputStream = try { | ||
Client.get(source) | ||
} catch (e: DavException) { | ||
throw e.toFileSystemException(source.toString()) | ||
} | ||
try { | ||
val targetOutputStream = try { | ||
Client.put(target) | ||
} catch (e: DavException) { | ||
throw e.toFileSystemException(target.toString()) | ||
} | ||
var successful = false | ||
try { | ||
sourceInputStream.copyTo( | ||
targetOutputStream, copyOptions.progressIntervalMillis, | ||
copyOptions.progressListener | ||
) | ||
successful = true | ||
} finally { | ||
try { | ||
targetOutputStream.close() | ||
} catch (e: DavException) { | ||
throw e.toFileSystemException(target.toString()) | ||
} finally { | ||
if (!successful) { | ||
try { | ||
Client.delete(target) | ||
} catch (e: DavException) { | ||
e.printStackTrace() | ||
} | ||
} | ||
} | ||
} | ||
} finally { | ||
try { | ||
sourceInputStream.close() | ||
} catch (e: DavException) { | ||
throw e.toFileSystemException(source.toString()) | ||
} | ||
} | ||
} | ||
} | ||
// We don't take error when copying attribute fatal, so errors will only be logged from now | ||
// on. | ||
if (!sourceResponse.isSymbolicLink) { | ||
val lastModifiedTime = sourceResponse.lastModifiedTime | ||
if (lastModifiedTime != null) { | ||
try { | ||
Client.setLastModifiedTime(target, lastModifiedTime) | ||
} catch (e: DavException) { | ||
e.printStackTrace() | ||
} | ||
} | ||
} | ||
} | ||
|
||
@Throws(IOException::class) | ||
fun move(source: WebDavPath, target: WebDavPath, copyOptions: CopyOptions) { | ||
val sourceResponse = try { | ||
Client.findProperties(source, copyOptions.noFollowLinks) | ||
} catch (e: DavException) { | ||
throw e.toFileSystemException(source.toString()) | ||
} | ||
val targetResponse = try { | ||
Client.findPropertiesOrNull(target, true) | ||
} catch (e: DavException) { | ||
throw e.toFileSystemException(target.toString()) | ||
} | ||
val sourceSize = sourceResponse.size | ||
if (targetResponse != null) { | ||
if (source == target) { | ||
copyOptions.progressListener?.invoke(sourceSize) | ||
return | ||
} | ||
if (!copyOptions.replaceExisting) { | ||
throw FileAlreadyExistsException(source.toString(), target.toString(), null) | ||
} | ||
try { | ||
Client.delete(target) | ||
} catch (e: DavException) { | ||
throw e.toFileSystemException(target.toString()) | ||
} | ||
} | ||
var renameSuccessful = false | ||
try { | ||
Client.move(source, target) | ||
renameSuccessful = true | ||
} catch (e: DavException) { | ||
if (copyOptions.atomicMove) { | ||
throw e.toFileSystemException(source.toString(), target.toString()) | ||
} | ||
// Ignored. | ||
} | ||
if (renameSuccessful) { | ||
copyOptions.progressListener?.invoke(sourceSize) | ||
return | ||
} | ||
if (copyOptions.atomicMove) { | ||
throw AssertionError() | ||
} | ||
var copyOptions = copyOptions | ||
if (!copyOptions.copyAttributes || !copyOptions.noFollowLinks) { | ||
copyOptions = CopyOptions( | ||
copyOptions.replaceExisting, true, false, true, copyOptions.progressIntervalMillis, | ||
copyOptions.progressListener | ||
) | ||
} | ||
copy(source, target, copyOptions) | ||
try { | ||
Client.delete(source) | ||
} catch (e: DavException) { | ||
if (e.toFileSystemException(source.toString()) !is NoSuchFileException) { | ||
try { | ||
Client.delete(target) | ||
} catch (e2: DavException) { | ||
e.addSuppressed(e2.toFileSystemException(target.toString())) | ||
} | ||
} | ||
throw e.toFileSystemException(source.toString()) | ||
} | ||
} | ||
} |
Oops, something went wrong.