Skip to content

Commit

Permalink
Merge pull request #1 from umjammer/1.0.2
Browse files Browse the repository at this point in the history
1.0.2
  • Loading branch information
umjammer authored Sep 11, 2023
2 parents 60c2ddd + a43dafe commit f7ac6da
Show file tree
Hide file tree
Showing 16 changed files with 199 additions and 46 deletions.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,28 @@
[![Java CI](https://github.com/umjammer/commons-vfs2-smb/actions/workflows/maven.yml/badge.svg)](https://github.com/umjammer/commons-vfs2-smb/actions/workflows/maven.yml)
[![CodeQL](https://github.com/umjammer/commons-vfs2-smb/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/umjammer/commons-vfs2-smb/actions/workflows/codeql-analysis.yml)
![Java](https://img.shields.io/badge/Java-8-b07219)
[![Parent](https://img.shields.io/badge/Parent-vavi--apps--fuse-pink)](https://github.com/umjammer/vavi-apps-fuse)

# commons-vfs2-smb

A production tested SMB FileSystemProvider for [Apache commons-vfs2](https://commons.apache.org/proper/commons-vfs/) based on [smbj](https://github.com/hierynomus/smbj).

Introduction
------------
## Introduction

This project implements required commons-vfs2 interfaces to allow interaction with SMB 2/3 using [Jeroen van Erp](https://github.com/hierynomus)'s [smbj](https://github.com/hierynomus/smbj) implementation.

I've created this library for a project that has been running in production for same time, and the features I've implemented were the ones I needed.

In case you are missing some feature, feel free to [file a bug](https://github.com/mikhasd/commons-vfs2-smb/issues/new) or send a Pull Request.

## Install

Usage
-----
* [maven](https://jitpack.io/#umjammer/commons-vfs2-smb)

## Usage

I'm still working on having a proper CI pipeline setup and the library uploaded to Maven Central. Any help is welcome.

```java
VFS.getManager().resolveFile("smb://DOMAIN\USERNAME:PASSWORD@HOSTNAME:PORT/SHARENAME/PATH");
VFS.getManager().resolveFile("smb://DOMAIN\\USERNAME:PASSWORD@HOSTNAME:PORT/SHARENAME/PATH");
```
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.github.mikhasd</groupId>
<artifactId>commons-vfs2-smb</artifactId>
<version>1.0.1</version>
<version>1.0.2</version>

<scm>
<connection>scm:git:git://github.com/mikhasd/commons-vfs2-smb.git</connection>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@

import java.util.Objects;


public class DiskShareManager {

private final SessionFactory sessionFactory;
private final String shareName;
private DiskShare diskShare;


public DiskShareManager(SessionFactory sessionFactory, String shareName) {
this.sessionFactory = sessionFactory;
this.shareName = shareName;
}

public DiskShare getDiskShare() throws SmbProviderException {
if(!isConnected()){
if (!isConnected()) {
Session session = this.sessionFactory.create();
this.diskShare = (DiskShare) session.connectShare(this.shareName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.hierynomus.msfscc.FileAttributes;
import com.hierynomus.msfscc.fileinformation.FileAllInformation;
import com.hierynomus.msfscc.fileinformation.FileIdBothDirectoryInformation;
import com.hierynomus.msfscc.fileinformation.FileInformation;
import com.hierynomus.mssmb2.SMB2CreateDisposition;
import com.hierynomus.mssmb2.SMB2CreateOptions;
import com.hierynomus.mssmb2.SMB2ShareAccess;
Expand All @@ -19,6 +18,7 @@
import java.util.function.Consumer;
import java.util.function.Function;


class DiskShareWrapper {

private final DiskShareManager diskShareManager;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.io.IOException;
import java.util.Objects;


public class SessionFactory {

private final static SmbConfig CONFIG = SmbConfig.builder()
Expand All @@ -27,7 +28,7 @@ public SessionFactory(String hostname, String domain, String username, String pa
}

private AuthenticationContext createAuthenticationContext(String domain, String username, String password) {
if(Objects.isNull(username) || username.trim().isEmpty())
if (Objects.isNull(username) || username.trim().isEmpty())
return AuthenticationContext.anonymous();
return new AuthenticationContext(username, password.toCharArray(), domain);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import java.util.Objects;


public class SmbFileName extends GenericFileName {

static final int DEFAULT_PORT = 136;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import java.util.Objects;


public class SmbFileNameParser extends GenericURLFileNameParser {

public SmbFileNameParser() {
Expand All @@ -19,21 +20,21 @@ public SmbFileNameParser() {
public FileName parseUri(VfsComponentContext context, FileName base, String fileName) throws FileSystemException {
StringBuilder builder = new StringBuilder(128);

final Authority auth = extractToPath(fileName, builder);
final String usernameAndDomain = auth.getUserName();
final String domain = extractDomain(usernameAndDomain);
final String username = Objects.isNull(domain) ? usernameAndDomain : usernameAndDomain.substring(domain.length() + 1);
Authority auth = extractToPath(context, fileName, builder);
String usernameAndDomain = auth.getUserName();
String domain = extractDomain(usernameAndDomain);
String username = Objects.isNull(domain) ? usernameAndDomain : usernameAndDomain.substring(domain.length() + 1);

UriParser.canonicalizePath(builder, 0, builder.length(), this);
UriParser.fixSeparators(builder);

final String share = UriParser.extractFirstElement(builder);
String share = UriParser.extractFirstElement(builder);
if(Objects.isNull(share) || share.trim().isEmpty()){
throw SmbProviderException.missingShareName(fileName);
}

final FileType fileType = UriParser.normalisePath(builder);
final String path = builder.toString();
FileType fileType = UriParser.normalisePath(builder);
String path = builder.toString();

return new SmbFileName(
auth.getScheme(),
Expand All @@ -50,17 +51,17 @@ public FileName parseUri(VfsComponentContext context, FileName base, String file

@Override
protected String extractUserInfo(StringBuilder name) {
final int atSign = name.lastIndexOf("@");
int atSign = name.lastIndexOf("@");
if(atSign < 0){
return null;
}
final String userInfo = name.substring(0, atSign);
String userInfo = name.substring(0, atSign);
name.delete(0, atSign +1);
return userInfo;
}

private String extractDomain(String username) {
final int backslash;
int backslash;
if(Objects.isNull(username) || (backslash = username.indexOf('\\')) <= 0){
return null;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import static org.apache.commons.vfs2.FileType.FOLDER;
import static org.apache.commons.vfs2.FileType.IMAGINARY;


public class SmbFileObject extends AbstractFileObject<SmbFileSystem> {

private final SmbTemplate smbTemplate;
Expand Down Expand Up @@ -79,7 +80,8 @@ protected InputStream doGetInputStream() throws Exception {
}

@Override
protected OutputStream doGetOutputStream(final boolean append) throws Exception {
protected OutputStream doGetOutputStream(boolean append) throws Exception {
@SuppressWarnings("resource")
File file = smbTemplate.openFileForWrite(path);
return new FilterOutputStream(file.getOutputStream(append)) {
@Override public void close() throws IOException { super.close(); file.close(); }
Expand Down Expand Up @@ -125,7 +127,7 @@ protected void doCreateFolder() throws Exception {

@Override
protected void doRename(FileObject newFile) throws Exception {
final DiskEntry entry;
DiskEntry entry;
if (isFolder()) {
entry = smbTemplate.openFolderForWrite(path);
} else {
Expand All @@ -150,12 +152,12 @@ public void copyFrom_(FileObject file, FileSelector selector) throws FileSystemE
throw SmbProviderException.missingSourceFile(file);
}

final List<FileObject> files = new ArrayList<>();
List<FileObject> files = new ArrayList<>();
file.findFiles(selector, false, files);

for (FileObject srcFile : files) {
final String relativePath = file.getName().getRelativeName(srcFile.getName());
final FileObject destinationFile = resolveFile(relativePath, NameScope.DESCENDENT_OR_SELF);
String relativePath = file.getName().getRelativeName(srcFile.getName());
FileObject destinationFile = resolveFile(relativePath, NameScope.DESCENDENT_OR_SELF);

FileType srcFileType = srcFile.getType();
if (destinationFile.exists() && !destinationFile.getType().equals(srcFileType)) {
Expand All @@ -172,7 +174,7 @@ public void copyFrom_(FileObject file, FileSelector selector) throws FileSystemE
} else if (srcFileType.hasChildren()) {
destinationFile.createFolder();
}
} catch (final IOException ioex) {
} catch (IOException ioex) {
throw new FileSystemException("vfs.provider/copy-file.error", ioex, srcFile, destinationFile);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import static org.apache.commons.vfs2.Capability.*;
import static org.apache.commons.vfs2.UserAuthenticationData.*;


public class SmbFileProvider extends AbstractOriginatingFileProvider {

static final Collection<Capability> CAPABILITIES = EnumSet.of(
Expand Down Expand Up @@ -38,20 +39,20 @@ public SmbFileProvider() {

@Override
protected FileSystem doCreateFileSystem(FileName rootName, FileSystemOptions fileSystemOptions) throws FileSystemException {
final SmbFileName smbRootName = (SmbFileName) rootName;
final DiskShareWrapper diskShareWrapper = createDiskShareConnection(smbRootName, fileSystemOptions);
final SmbTemplate smbTemplate = new SmbTemplate(diskShareWrapper);
SmbFileName smbRootName = (SmbFileName) rootName;
DiskShareWrapper diskShareWrapper = createDiskShareConnection(smbRootName, fileSystemOptions);
SmbTemplate smbTemplate = new SmbTemplate(diskShareWrapper);
return new SmbFileSystem(rootName, fileSystemOptions, smbTemplate);
}

private DiskShareWrapper createDiskShareConnection(SmbFileName smbRootName, FileSystemOptions fileSystemOptions) {

final String hostname = smbRootName.getHostName();
final String share = smbRootName.getShare();
String hostname = smbRootName.getHostName();
String share = smbRootName.getShare();

final String username;
final String password;
final String domain;
String username;
String password;
String domain;

Optional<UserAuthenticationData> authenticationData = getAuthenticationData(fileSystemOptions);

Expand All @@ -67,8 +68,8 @@ private DiskShareWrapper createDiskShareConnection(SmbFileName smbRootName, File
}


final SessionFactory sessionFactory = new SessionFactory(hostname, domain, username, password);
final DiskShareManager diskShareManager = new DiskShareManager(sessionFactory, share);
SessionFactory sessionFactory = new SessionFactory(hostname, domain, username, password);
DiskShareManager diskShareManager = new DiskShareManager(sessionFactory, share);
return new DiskShareWrapper(diskShareManager);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import java.util.Collection;


public class SmbFileSystem extends AbstractFileSystem {
private final SmbTemplate smbTemplate;

Expand All @@ -24,5 +25,4 @@ protected SmbFileObject createFile(AbstractFileName name) {
protected void addCapabilities(Collection<Capability> caps) {
caps.addAll(SmbFileProvider.CAPABILITIES);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import java.io.IOException;
import java.io.InputStream;


public class SmbInputStream extends InputStream {

private final File file;
private final InputStream inputStream;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package com.github.mikhasd.vfs2.provider.smb;


import com.hierynomus.mssmb2.SMBApiException;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;

import java.io.IOException;


public class SmbProviderException extends FileSystemException {

private static final String CONNECTION_ERROR = "vfs.provider.smb/connection.error";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
import static com.hierynomus.mssmb2.SMB2ShareAccess.FILE_SHARE_WRITE;
import static java.util.EnumSet.of;


public class SmbTemplate {

private final DiskShareWrapper diskShareWrapper;

public SmbTemplate(DiskShareWrapper diskShareWrapper) {
SmbTemplate(DiskShareWrapper diskShareWrapper) {
this.diskShareWrapper = diskShareWrapper;
}

Expand Down
15 changes: 9 additions & 6 deletions src/test/java/SmbjTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
import com.hierynomus.smbj.share.DiskShare;
import com.hierynomus.smbj.share.File;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIf;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariables;
import vavi.util.Debug;

import static com.hierynomus.msdtyp.AccessMask.DELETE;
Expand All @@ -43,10 +44,6 @@
*/
public class SmbjTest {

static boolean localPropertiesExists() {
return Files.exists(Paths.get("local.properties"));
}

static {
// TODO move to pom.xml
System.setProperty("vavi.util.logging.VaviFormatter.extraClassMethod",
Expand All @@ -69,7 +66,13 @@ static boolean localPropertiesExists() {
* - according to cyberduck it works with smbj 0.12.2 https://github.com/hierynomus/smbj/issues/584#issuecomment-1694759650
*/
@Test
@EnabledIf("localPropertiesExists")
@EnabledIfEnvironmentVariables({
@EnabledIfEnvironmentVariable(named = "TEST_SMB_ACCOUNT", matches = ".+"),
@EnabledIfEnvironmentVariable(named = "TEST_SMB_PASSWORD", matches = ".+"),
@EnabledIfEnvironmentVariable(named = "TEST_SMB_HOST", matches = ".+"),
@EnabledIfEnvironmentVariable(named = "TEST_SMB_DOMAIN", matches = ".+"),
@EnabledIfEnvironmentVariable(named = "TEST_SMB_PATH", matches = ".+"),
})
void test_smbj() throws Exception {
String username = System.getenv("TEST_SMB_ACCOUNT");
String password = System.getenv("TEST_SMB_PASSWORD");
Expand Down
Loading

0 comments on commit f7ac6da

Please sign in to comment.