Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
371fc91
Fix StubSmbServer on Windows
dgodfrey Mar 31, 2024
d42eb71
Don't re-build image for every integrationTest
dgodfrey Apr 23, 2024
e34dcae
Allow SmbFileSystems to be created
dgodfrey Sep 12, 2022
1dcb483
Allow SmbFileSystems to be closed
dgodfrey Apr 23, 2024
15e4472
Implement basic Path functionality and getRootDirectories
dgodfrey Apr 23, 2024
bdde306
Support Files#newDirectoryStream
dgodfrey Apr 23, 2024
13b4117
Support BasicFileAttributes
dgodfrey Apr 23, 2024
ff7b2b8
Support Files#exists
dgodfrey Sep 27, 2022
24f8001
Support reading files
dgodfrey Apr 23, 2024
a432c0e
Support writing files
dgodfrey Sep 28, 2022
6a155f1
Basic file copy support
dgodfrey Apr 23, 2024
175d98d
Support Paths#get(URI)
dgodfrey Oct 22, 2024
e22a0f6
Basic move support
dgodfrey Oct 23, 2024
e9fa0a4
Basic delete support
dgodfrey Oct 23, 2024
9697d7b
Support moving files between shares
dgodfrey Oct 23, 2024
f1e30f9
Support creating directories
dgodfrey Oct 23, 2024
8a19fab
Support multiple folders in single path component
dgodfrey Nov 27, 2024
25b6f5e
No need to pass Connection into SmbFileSystem
dgodfrey Dec 19, 2024
a7436c8
Hide share creation behind an interface
dgodfrey Dec 19, 2024
d506531
Introduce Holder class to allow connections to be shut after use
dgodfrey Dec 19, 2024
bf96d71
Reconnect to share for every operation
dgodfrey Dec 19, 2024
b2fa80e
Use credentials from environment, if present
dgodfrey Jan 15, 2025
067b8ef
Add equals and hashCode methods to smbfs.SmbPath
dgodfrey Jan 15, 2025
af2cbe2
Simplify smbfs.SmbPathTest with a factory method
dgodfrey Jan 15, 2025
dd8016c
Rewrite smbfs.SmbPathTest with @ParameterizedTest
dgodfrey Jan 15, 2025
fe7756a
Implement SmbPath#resolveSibling
dgodfrey Jan 16, 2025
4f67843
Normalise and combine paths in SmbFileSystem
dgodfrey Jan 16, 2025
3c90066
Use SmbFileSystem in SmbPathTest
dgodfrey Jan 16, 2025
362d372
Remove normalisation from SmbPath and reanme of -> parse
dgodfrey Jan 16, 2025
ddfe803
Fix some bugs around root paths
dgodfrey Jan 16, 2025
1b61d92
Represent root Path with empty List
dgodfrey Jan 16, 2025
02c2c84
Implement SmbPath#startsWith
dgodfrey Jan 16, 2025
33d56b8
Implement SmbPath#endsWith
dgodfrey Jan 16, 2025
ce77e75
Signify root-paths using a null elements field
dgodfrey Jan 29, 2025
393ce62
Implement SmbPath#relativize
dgodfrey Jan 29, 2025
9a61c63
Test integration with java.nio.files package
dgodfrey Jan 30, 2025
0ad5f6d
Add info about FileSystem to README.adoc
dgodfrey Jan 30, 2025
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
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@
*.sh text eol=lf
*.java text
*.scala text

# Keep these src files in binary as used for testing
src/it/docker-image/public/**/* binary
39 changes: 39 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,45 @@ C - Adjusting Timeout and Socket Timeout

```

=== Using the java.nio.file.FileSystem implementation

Smbj registers a new FileSystem provider with the smb:// URLs for accessing SMB shares.

NB. This is not 100% implemented as-yet, although it works for basic usage. See below for unimplemented features.

A - Writing a file with a temporary filename, before moving to the final location

```java

// Create the filesystem
Map<String, Object> env = new HashMap<>();
// optional, leave blank for anonymous access to the share
env.put(SmbFileSystemProvider.DOMAIN_PROPERTY, "domain");
env.put(SmbFileSystemProvider.USERNAME_PROPERTY, "userName");
env.put(SmbFileSystemProvider.PASSWORD_PROPERTY, "password".toCharArray());
FileSystems.newFileSystem(URI.create("smb://<hostname>/<sharename>"), env);

...

// Write a file with a temporary name to ensure nobody reads while writing
Path path = Paths.get(URI.Create("smb://<hostname>/<sharename>/aFolder/file.txt"));
Path workingPath = path.resolveSibling(path.getFileName().toString() + ".working");

Files.createDirectories(workingPath.getParent());
try (Writer w = Files.newBufferedWriter(workingPath)) {
w.write("Hello World");
}
Files.move(workingPath, path);
```

==== Unimplemented features

* SMBException -> IOException translation
* WatchService
* file attributes
* FileStores
* UserPrincipalLookupService

== Frequently Asked Questions

=== When I run my code I get an `SMBApiException` with the message `STATUS_... (0x...)`. What am I doing wrong?
Expand Down
6 changes: 4 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import com.bmuschko.gradle.docker.tasks.container.*
import com.bmuschko.gradle.docker.tasks.image.*
import java.text.SimpleDateFormat

plugins {
id "java"
Expand Down Expand Up @@ -50,6 +49,7 @@ dependencies {
implementation BCPROV_JDK15ON
implementation MBASSADOR
implementation ASN_ONE
testImplementation GUAVA_TESTLIB
}

license {
Expand Down Expand Up @@ -96,7 +96,9 @@ testing {
runtimeOnly OBJENESIS
implementation SPOCK_CORE
implementation COMMONS_IO
implementation "org.mockito:mockito-core:5.4.0"
implementation enforcedPlatform("org.mockito:mockito-bom:5.4.0")
implementation "org.mockito:mockito-core"
implementation "org.mockito:mockito-junit-jupiter"
implementation "org.assertj:assertj-core:3.24.2"
runtimeOnly LOGBACK_CLASSIC
}
Expand Down
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
BCPROV_JDK15ON=org.bouncycastle:bcprov-jdk18on:1.79
CGLIB_NODEP=cglib:cglib-nodep:3.3.0
COMMONS_IO=commons-io:commons-io:2.16.1
GUAVA_TESTLIB=com.google.guava:guava-testlib:33.4.0-jre
LOGBACK_CLASSIC=ch.qos.logback:logback-classic:1.5.6
MBASSADOR=net.engio:mbassador:1.3.0
OBJENESIS=org.objenesis:objenesis:3.4
Expand Down
2 changes: 1 addition & 1 deletion src/it/docker-image/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ COPY entrypoint.sh /entrypoint.sh
ADD public /opt/samba/share

RUN mkdir -p /opt/samba/readonly /opt/samba/user /opt/samba/dfs && \
chmod 777 /opt/samba/readonly /opt/samba/user /opt/samba/dfs && \
chmod 777 /opt/samba/readonly /opt/samba/user /opt/samba/dfs /opt/samba/share && \
adduser -s /bin/false "$SMB_USER" -D $SMB_PASSWORD && \
(echo "$SMB_PASSWORD"; echo "$SMB_PASSWORD" ) | pdbedit -a -u "$SMB_USER" && \
chmod ugo+x /entrypoint.sh
Expand Down
24 changes: 13 additions & 11 deletions src/it/java/com/hierynomus/smbj/AnonymousIntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,6 @@
*/
package com.hierynomus.smbj;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import com.hierynomus.mssmb2.SMB2Dialect;
import com.hierynomus.security.bc.BCSecurityProvider;
import com.hierynomus.smbj.auth.AuthenticationContext;
Expand All @@ -30,18 +23,27 @@
import com.hierynomus.smbj.share.DiskShare;
import com.hierynomus.smbj.share.Share;
import com.hierynomus.smbj.testcontainers.SambaContainer;

import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import java.util.stream.Stream;

import static com.hierynomus.smbj.testing.TestingUtils.*;
import static com.hierynomus.smbj.testing.TestingUtils.config;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

@Testcontainers
public class AnonymousIntegrationTest {

@Container
private static final SambaContainer samba = new SambaContainer.Builder().build();
private static final SambaContainer samba = SambaContainer.INSTANCE;

static Stream<Arguments> connectWith() {
return Stream.of(
Expand Down
36 changes: 18 additions & 18 deletions src/it/java/com/hierynomus/smbj/ChangeNotifyIntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,6 @@
*/
package com.hierynomus.smbj;

import static com.hierynomus.mssmb2.SMB2CompletionFilter.FILE_NOTIFY_CHANGE_FILE_NAME;
import static com.hierynomus.mssmb2.SMB2CompletionFilter.FILE_NOTIFY_CHANGE_LAST_WRITE;
import static com.hierynomus.mssmb2.SMB2CompletionFilter.FILE_NOTIFY_CHANGE_SIZE;
import static com.hierynomus.smbj.testing.TestingUtils.DEFAULT_AUTHENTICATION_CONTEXT;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

import java.nio.charset.StandardCharsets;
import java.util.EnumSet;
import java.util.concurrent.Future;

import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import com.hierynomus.msdtyp.AccessMask;
import com.hierynomus.msfscc.FileAttributes;
import com.hierynomus.msfscc.FileNotifyAction;
Expand All @@ -46,11 +29,28 @@
import com.hierynomus.smbj.share.DiskShare;
import com.hierynomus.smbj.share.File;
import com.hierynomus.smbj.testcontainers.SambaContainer;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import java.nio.charset.StandardCharsets;
import java.util.EnumSet;
import java.util.concurrent.Future;

import static com.hierynomus.mssmb2.SMB2CompletionFilter.FILE_NOTIFY_CHANGE_FILE_NAME;
import static com.hierynomus.mssmb2.SMB2CompletionFilter.FILE_NOTIFY_CHANGE_LAST_WRITE;
import static com.hierynomus.mssmb2.SMB2CompletionFilter.FILE_NOTIFY_CHANGE_SIZE;
import static com.hierynomus.smbj.testing.TestingUtils.DEFAULT_AUTHENTICATION_CONTEXT;
import static org.assertj.core.api.Assertions.as;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

@Testcontainers
public class ChangeNotifyIntegrationTest {
@Container
private static final SambaContainer samba = new SambaContainer.Builder().build();
private static final SambaContainer samba = SambaContainer.INSTANCE;

@ParameterizedTest(name = "should watch changes")
@MethodSource("com.hierynomus.smbj.testing.TestingUtils#defaultTestingConfig")
Expand Down
23 changes: 11 additions & 12 deletions src/it/java/com/hierynomus/smbj/DfsIntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,6 @@
*/
package com.hierynomus.smbj;

import static com.hierynomus.smbj.testing.TestingUtils.DEFAULT_AUTHENTICATION_CONTEXT;
import static org.assertj.core.api.Assertions.assertThat;

import java.util.EnumSet;
import java.util.List;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import com.hierynomus.msdtyp.AccessMask;
import com.hierynomus.msfscc.fileinformation.FileIdBothDirectoryInformation;
import com.hierynomus.mssmb2.SMB2CreateDisposition;
Expand All @@ -34,11 +23,21 @@
import com.hierynomus.smbj.share.DiskShare;
import com.hierynomus.smbj.testcontainers.SambaContainer;
import com.hierynomus.smbj.testing.TestingUtils.ConsumerWithError;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import java.util.EnumSet;
import java.util.List;

import static com.hierynomus.smbj.testing.TestingUtils.DEFAULT_AUTHENTICATION_CONTEXT;
import static org.assertj.core.api.Assertions.assertThat;

@Testcontainers
public class DfsIntegrationTest {
@Container
private static final SambaContainer samba = new SambaContainer.Builder().build();
private static final SambaContainer samba = SambaContainer.INSTANCE;

@ParameterizedTest(name = "should connect to DFS share")
@MethodSource("com.hierynomus.smbj.testing.TestingUtils#dfsConfig")
Expand Down
25 changes: 12 additions & 13 deletions src/it/java/com/hierynomus/smbj/IntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,29 @@
*/
package com.hierynomus.smbj;

import static com.hierynomus.smbj.testing.TestingUtils.DEFAULT_AUTHENTICATION_CONTEXT;
import static org.assertj.core.api.Assertions.as;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

import java.util.List;

import com.hierynomus.msfscc.fileinformation.FileIdBothDirectoryInformation;
import com.hierynomus.mssmb2.SMB2Dialect;
import com.hierynomus.smbj.share.DiskShare;
import com.hierynomus.smbj.share.Share;
import com.hierynomus.smbj.testcontainers.SambaContainer;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import com.hierynomus.msfscc.fileinformation.FileIdBothDirectoryInformation;
import com.hierynomus.mssmb2.SMB2Dialect;
import com.hierynomus.smbj.share.DiskShare;
import com.hierynomus.smbj.share.Share;
import com.hierynomus.smbj.testcontainers.SambaContainer;
import java.util.List;

import static com.hierynomus.smbj.testing.TestingUtils.DEFAULT_AUTHENTICATION_CONTEXT;
import static org.assertj.core.api.Assertions.as;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

@Testcontainers
public class IntegrationTest {
@Container
private static final SambaContainer samba = new SambaContainer.Builder().build();
private static final SambaContainer samba = SambaContainer.INSTANCE;

@ParameterizedTest(name = "should connect")
@MethodSource("com.hierynomus.smbj.testing.TestingUtils#defaultTestingConfig")
Expand Down
21 changes: 10 additions & 11 deletions src/it/java/com/hierynomus/smbj/SMB2DirectoryIntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,6 @@
*/
package com.hierynomus.smbj;

import java.nio.charset.StandardCharsets;
import java.util.EnumSet;
import java.util.List;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import com.hierynomus.msdtyp.AccessMask;
import com.hierynomus.msfscc.fileinformation.FileIdBothDirectoryInformation;
import com.hierynomus.mssmb2.SMB2CreateDisposition;
Expand All @@ -34,16 +25,24 @@
import com.hierynomus.smbj.share.DiskShare;
import com.hierynomus.smbj.share.File;
import com.hierynomus.smbj.testcontainers.SambaContainer;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import java.nio.charset.StandardCharsets;
import java.util.EnumSet;
import java.util.List;

import static com.hierynomus.smbj.testing.TestingUtils.*;
import static com.hierynomus.smbj.testing.TestingUtils.DEFAULT_AUTHENTICATION_CONTEXT;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

@Testcontainers
public class SMB2DirectoryIntegrationTest {

@Container
private static final SambaContainer samba = new SambaContainer.Builder().build();
private static final SambaContainer samba = SambaContainer.INSTANCE;

@ParameterizedTest(name = "should open directory")
@MethodSource("com.hierynomus.smbj.testing.TestingUtils#defaultTestingConfig")
Expand Down
Loading