pontiussoftware / smb-nio Goto Github PK
View Code? Open in Web Editor NEWA Java NIO.2 wrapper to access SMB file systems.
License: MIT License
A Java NIO.2 wrapper to access SMB file systems.
License: MIT License
I'm testing this against a read-only SMB share, and trying to read a file (via Files.copy()
) results in a permission error:
jcifs.smb.SmbAuthException: Access is denied.
at jcifs.smb.SmbTransport.checkStatus(SmbTransport.java:546)
at jcifs.smb.SmbTransport.send(SmbTransport.java:640)
at jcifs.smb.SmbSession.send(SmbSession.java:238)
at jcifs.smb.SmbTree.send(SmbTree.java:119)
at jcifs.smb.SmbFile.send(SmbFile.java:775)
at jcifs.smb.SmbFile.setPathInformation(SmbFile.java:2578)
at jcifs.smb.SmbFile.setAttributes(SmbFile.java:2646)
at jcifs.smb.SmbFile.setReadOnly(SmbFile.java:2656)
at ch.pontius.nio.smb.SeekableSMBByteChannel.<init>(SeekableSMBByteChannel.java:49)
at ch.pontius.nio.smb.SMBFileSystemProvider.newByteChannel(SMBFileSystemProvider.java:196)
at java.nio.file.Files.newByteChannel(Files.java:361)
at java.nio.file.Files.newByteChannel(Files.java:407)
at java.nio.file.spi.FileSystemProvider.newInputStream(FileSystemProvider.java:384)
at java.nio.file.Files.newInputStream(Files.java:152)
at java.nio.file.Files.copy(Files.java:3068)
It seems the problem is that SeekableSMBByteChannel
is calling SmbFile.setReadOnly()
, which is telling the server to make the file read-only. That's not really what a read operation should be doing.
Hi there, the example usage states SmbFileSystemProvider.getDefault()
but the getDefault() method does not exist in this class.
Also the case is wrong, should be SMBFileSystemProvider.
https://github.com/jfrommann/smb-nio-ng. I am writing here because the tracker is not available in another repository.
Exception:
Exception in thread "main" jcifs.smb.SmbException: smb://username:pasword@server//dir1/dir2 directory must end with '/'
at jcifs.smb.DirFileEntryEnumIterator1.open(DirFileEntryEnumIterator1.java:57)
at jcifs.smb.DirFileEntryEnumIteratorBase.<init>(DirFileEntryEnumIteratorBase.java:67)
at jcifs.smb.DirFileEntryEnumIterator1.<init>(DirFileEntryEnumIterator1.java:46)
at jcifs.smb.SmbEnumerationUtil.doEnum(SmbEnumerationUtil.java:225)
at jcifs.smb.SmbEnumerationUtil.listFiles(SmbEnumerationUtil.java:279)
at jcifs.smb.SmbFile.listFiles(SmbFile.java:1199)
at com.github.jfrommann.nio.smb.SmbDirectoryStream.<init>(SmbDirectoryStream.java:43)
at com.github.jfrommann.nio.smb.SmbFileSystemProvider.newDirectoryStream(SmbFileSystemProvider.java:382)
at java.base/java.nio.file.Files.newDirectoryStream(Files.java:476)
at java.base/java.nio.file.Files.newDirectoryStream(Files.java:533)
at kotlin.io.path.PathsKt__PathUtilsKt.listDirectoryEntries(PathUtils.kt:342)
at kotlin.io.path.PathsKt__PathUtilsKt.listDirectoryEntries$default(PathUtils.kt:341)
// my call code
Code:
val fileSystem: SmbFileSystem = SmbFileSystemProvider
.getDefault()
.newFileSystem(URI.create("smb://server/"), environment)
fileSystem.getPath("dir1", "dir2") // .normalize() analogy effetc, work: getPath("dir1", "dir2/")
.listDirectoryEntries() // Files.newDirectoryStream(path, "*").use { sream -> stream.toList() } // use - AutoCLoseble Stream
.forEach(::println)
When SMBDirectoryStream is used to iterate over directory with subdirectories, the trailing slashes are not added for these subdirectories. This is violating jcifs requirement that all directories must have trailing slash and some operations (e.g. attempt to iterate over these subdirectories) will throw "jcifs.smb.SmbException: directory must end with '/'".
As a result, it is not possible to use Files.walkFileTree(...) method to walk over any smb-nio filesystem with maxDepth bigger than 1.
JCIFS provides the concept of subcontexts and allows retrieving a resource from a subcontext:
NtlmPasswordAuthenticator auth = new NtlmPasswordAuthenticator("mydomain", "myuser", "mypass"); <br/> CIFSContext cifsContext = SingletonContext.getInstance().withCredentials(auth); <br/> SmbResource smbResource = cifsContext.get(uriStr); <br/> smbResource.children().forEachRemaining(p -> { System.out.println(p); });<br/>
Is there a possibility to use NtlmPasswordAuthenticator with your library?
Cheers,
Kai
jcifs-ng 2.1.8 uses an old verion of bcprov with new security issues.
In version 2.1.10 this dependency is renewed to a new verion of bcprov without those issues.
Seems after I added this library when I try to call my existing smb code to check whether a file/folder exists:
SmbFile userDir = new SmbFile(folder.getAsString(), getAuthToken())
if (!userDir.exists()) {
}
the call blows up with
org.springframework.messaging.MessageHandlingException: Unexpected handler method invocation error; nested exception is java.lang.IllegalAccessError: failed to access class org.bouncycastle.asn1.DEROutputStream from class jcifs.spnego.NegTokenInit (org.bouncycastle.asn1.DEROutputStream and jcifs.spnego.NegTokenInit are in unnamed module of loader org.springframework.boot.loader.LaunchedURLClassLoader @4678c730)
Caused by: java.lang.IllegalAccessError: failed to access class org.bouncycastle.asn1.DEROutputStream from class jcifs.spnego.NegTokenInit (org.bouncycastle.asn1.DEROutputStream and jcifs.spnego.NegTokenInit are in unnamed module of loader org.springframework.boot.loader.LaunchedURLClassLoader @4678c730)
at jcifs.spnego.NegTokenInit.toByteArray(NegTokenInit.java:158) ~[jcifs-2.1.7.jar!/:na]
at jcifs.smb.SpnegoContext.initSecContext(SpnegoContext.java:207) ~[jcifs-2.1.7.jar!/:na]
at jcifs.smb.SmbSessionImpl.createToken(SmbSessionImpl.java:656) ~[jcifs-2.1.7.jar!/:na]
at jcifs.smb.SmbSessionImpl.sessionSetupSMB2(SmbSessionImpl.java:538) ~[jcifs-2.1.7.jar!/:na]
at jcifs.smb.SmbSessionImpl.sessionSetup(SmbSessionImpl.java:483) ~[jcifs-2.1.7.jar!/:na]
at jcifs.smb.SmbSessionImpl.send(SmbSessionImpl.java:369) ~[jcifs-2.1.7.jar!/:na]
at jcifs.smb.SmbSessionImpl.send(SmbSessionImpl.java:347) ~[jcifs-2.1.7.jar!/:na]
at jcifs.smb.SmbTreeImpl.treeConnect(SmbTreeImpl.java:604) ~[jcifs-2.1.7.jar!/:na]
at jcifs.smb.SmbTreeConnection.connectTree(SmbTreeConnection.java:610) ~[jcifs-2.1.7.jar!/:na]
at jcifs.smb.SmbTreeConnection.connectHost(SmbTreeConnection.java:564) ~[jcifs-2.1.7.jar!/:na]
at jcifs.smb.SmbTreeConnection.connectHost(SmbTreeConnection.java:485) ~[jcifs-2.1.7.jar!/:na]
at jcifs.smb.SmbTreeConnection.connect(SmbTreeConnection.java:461) ~[jcifs-2.1.7.jar!/:na]
at jcifs.smb.SmbTreeConnection.connectWrapException(SmbTreeConnection.java:422) ~[jcifs-2.1.7.jar!/:na]
at jcifs.smb.SmbFile.ensureTreeConnected(SmbFile.java:551) ~[jcifs-2.1.7.jar!/:na]
at jcifs.smb.SmbFile.exists(SmbFile.java:838) ~[jcifs-2.1.7.jar!/:na]
Is this library compatible with other smb providers, namely spring-integration-smb?
Merge of 3d8fa4f ignores all environment settings for the context creation.
First of all, thanks for making this library publicly available!
I'm trying it out in our project, where I need to talk to a hardware device.
In the new firmware, SMBv1 was (finally ๐ ) disabled in favour of SMBv2/3.
Unfortunately, now we need to update our driver ๐
Based on the ReadMe example, I tried to do a very simple listing of directory contents on the hardware device, as follows:
@Test
public void testPontiusSmbNio() throws Exception {
SMBFileSystemProvider provider = new SMBFileSystemProvider();
Map<String, String> env = Map.of(
"jcifs.smb.client.username", Device.SMB_USER,
"jcifs.smb.client.password", Device.SMB_PASS,
"jcifs.smb.client.domain", ""
);
URI uri = new URI(String.format("smb://%s/%s/", Device.getIp(), SMB_ROOT));
System.out.println("uri = " + uri);
System.out.println("uri.getAuthority() = " + uri.getAuthority());
try (SMBFileSystem fs = provider.newFileSystem(uri, env)) {
labelDir = fs.getPath(Device.LABEL_DIR);
try (Stream<Path> dir = Files.list(labelDir)){
dir.forEach(label -> System.out.println("label = " + label));
}
}
}
Output is as follows:
uri = smb:///192.168.100.230/the-share/
uri.getAuthority() = null
java.lang.NullPointerException: Cannot invoke "String.contains(java.lang.CharSequence)" because the return value of "java.net.URI.getAuthority()" is null
java.lang.NullPointerException: Cannot invoke "String.contains(java.lang.CharSequence)" because the return value of "java.net.URI.getAuthority()" is null
at ch.pontius.nio.smb.SMBFileSystemProvider.constructAuthority(SMBFileSystemProvider.java:509)
at ch.pontius.nio.smb.SMBFileSystemProvider.newFileSystem(SMBFileSystemProvider.java:92)
at de.pharmacontrol.playground.smb.SmbNioTest.testPontiusSmbNio(SmbNioTest.java:33)
<snip JUnit internals>
Indeed, inside SMBFileSystemProvider, line 508, I see:
/* Check if URI encodes credentials. Credentials are used in the following order: */
if (uri.getAuthority().contains(SMBFileSystem.CREDENTIALS_SEPARATOR)) {
authority = uri.getAuthority();
which obviously doesn't like the null
.
Am I using it wrong, or should there be a null-check there?
Based on the readme-example, which puts the authentication info into the env
map, I wouldn't expect the URI-authority section to be required.
Passwords with certain URI-reserved characters, like /
and #
, present challenges.
If you use /
in the env map sent to SmbFileSystemProvider.newFilesystem(URI, Map)
, it is not percent-encoded before being concatenated into the URL that is fed into SmbFile, and you can get odd errors as a result.
For example, using username "foo" and password "bar/", you get
Exception in thread "main" java.net.MalformedURLException: For input string: "bar"
at java.net.URL.<init>(URL.java:627)
at jcifs.smb.SmbFile.<init>(SmbFile.java:485)
at ch.pontius.nio.smb.SMBPath.getSmbFile(SMBPath.java:488)
at ch.pontius.nio.smb.SMBFileSystemProvider.checkAccess(SMBFileSystemProvider.java:324)
at org.cru.smb.Test.main(Test.java:29)
Caused by: java.lang.NumberFormatException: For input string: "bar"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at java.net.URLStreamHandler.parseURL(URLStreamHandler.java:222)
at jcifs.smb.Handler.parseURL(Handler.java:51)
at java.net.URL.<init>(URL.java:622)
... 4 more
To work around this, I would have to percent-encode the password in the env map.
A related problem is when I put the password into the URI (and not the env map) that I pass in to SmbFileSystemProvider.newFilesystem(URI, Map)
. In this case, I have to percent-encode the password so that I can construct a valid URI.
But SMBFileSystemProvider decodes this password, and does not re-encode it, when it sends it on to SmbFile.
So a uri like smb://foo:bar%[email protected]/some_share
results in a stack trace like this:
Exception in thread "main" java.net.MalformedURLException: For input string: "bar"
at java.net.URL.<init>(URL.java:627)
at jcifs.smb.SmbFile.<init>(SmbFile.java:485)
at ch.pontius.nio.smb.SMBPath.getSmbFile(SMBPath.java:488)
at ch.pontius.nio.smb.SMBFileSystemProvider.checkAccess(SMBFileSystemProvider.java:324)
at org.cru.smb.Test.main(Test.java:42)
Caused by: java.lang.NumberFormatException: For input string: "bar"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at java.net.URLStreamHandler.parseURL(URLStreamHandler.java:222)
at jcifs.smb.Handler.parseURL(Handler.java:51)
at java.net.URL.<init>(URL.java:622)
... 4 more
To work around this, I would have to double percent-encode the password in the URI.
I tried your library and did not manage to get credentials in url working.
Not working:
try (final DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Path.of(URI.create("smb://user:[email protected]/test/")))) {
directoryStream.forEach(System.out::println);
}
Working:
System.setProperty("jcifs.smb.client.username", "user");
System.setProperty("jcifs.smb.client.password", "password");
try (final DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Path.of(URI.create("smb://192.168.0.6/test/")))) {
directoryStream.forEach(System.out::println);
}
From the README I suppose the first one is supposed to work also?
And version: smb-nio:0.12.0 & jcifs-ng:2.1.9 (also tried jcifs-ng:2.1.8 and smb-nio:0.11.0)
For example SMBFileSystemProvider currently does not override FileSystemProvider.newFileChannel() and generates a UnsupportedOperationException.
I think this could be implemented using SmbConstants.FILE_NO_SHARE "somehow".
SMBPath.resolve()
requires that the current path is a folder, which is fine, but it checks this by looking at whether the URI (or path) ends with a trailing slash. This seems incorrect to me; trailing slashes are generally optional, and java's default filesystem does't require trailing slashes to denote directories/folders.
I've got a SMBFileSystem
instance setup - which is working fine in terms of connecting - and want to get a Path
pointing to the root directory with the following call:
val myPath = fileSystem!!.getPath("/")
This however results in the following exception:
java.lang.ArrayIndexOutOfBoundsException: length=0; index=-1
at ch.pontius.nio.smb.SMBFileSystem.getPath(SMBFileSystem.java:178)
When looking into the source code, I see that the method getPath
does not allow for an empty more
array:
final String path = SMBPathUtil.mergePath(components, 0, components.length, first.startsWith("/"), more[more.length-1].endsWith("/"));
// here /\
// ||
Is this intended behavior or a bug?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.