All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.jborza.camel.component.smbj.SmbShare Maven / Gradle / Ivy

/*
 * Copyright [2018] [Juraj Borza]
 * 

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *

* http://www.apache.org/licenses/LICENSE-2.0 *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.github.jborza.camel.component.smbj; import com.github.jborza.camel.component.smbj.dfs.DfsResolutionResult; import com.github.jborza.camel.component.smbj.dfs.DfsResolver; import com.github.jborza.camel.component.smbj.exceptions.AttemptedRenameAcrossSharesException; import com.hierynomus.msdtyp.AccessMask; import com.hierynomus.msfscc.fileinformation.FileIdBothDirectoryInformation; import com.hierynomus.mssmb2.SMB2CreateDisposition; import com.hierynomus.mssmb2.SMB2CreateOptions; import com.hierynomus.mssmb2.SMB2ShareAccess; import com.hierynomus.smbj.SMBClient; import com.hierynomus.smbj.auth.AuthenticationContext; import com.hierynomus.smbj.common.SmbPath; import com.hierynomus.smbj.connection.Connection; import com.hierynomus.smbj.session.Session; import com.hierynomus.smbj.share.DiskShare; import com.hierynomus.smbj.share.File; import org.apache.camel.util.IOHelper; import org.apache.commons.io.IOUtils; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import static com.github.jborza.camel.component.smbj.SmbConstants.CURRENT_DIRECTORY; import static com.github.jborza.camel.component.smbj.SmbConstants.PARENT_DIRECTORY; public class SmbShare implements AutoCloseable { private final SMBClient client; private final SmbConfiguration config; private final boolean dfs; private final int bufferSize; private Session session; private String path; private DiskShare share; private ConnectionCache connectionCache; public SmbShare(SMBClient client, SmbConfiguration config, boolean dfs, int bufferSize) { this.client = client; this.config = config; this.dfs = dfs; this.bufferSize = bufferSize; connectionCache = new ConnectionCache(client); } private void connect(String targetPath) { session = connectSession(); DfsResolutionResult pathResolutionResult = resolvePlainPath(targetPath); String resolvedPath = pathResolutionResult.getSmbPath().getPath(); if (resolvedPath == null) resolvedPath = ""; path = removeLeadingBackslash(resolvedPath); share = pathResolutionResult.getDiskShare(); } private String removeLeadingBackslash(String path) { return path.replaceAll("^\\\\", ""); } private DfsResolutionResult resolvePlainPath(String targetPath) { String actualPath = SmbPathUtils.removeShareName(SmbPathUtils.convertToBackslashes(targetPath), config.getShare(), true); SmbPath targetSmbPath = new SmbPath(config.getHost(), config.getShare(), actualPath); return resolvePath(session, targetSmbPath); } @Override public void close() throws IOException { if (share != null) { share.close(); } //connection.close should close the active sessions for (Connection connection : connectionCache.getConnections()) { if (connection != null && connection.isConnected()) { connection.close(true); } } } /** * @return The connected share (either resolved by DFS or directly connected) */ public DiskShare getShare() { return share; } /** * @return The DFS resolved path, if DFS is used. Otherwise the supplied path is returned */ public String getPath() { return path; } private boolean isDfs() { return dfs; } private Session connectSession() { if (config.isDefaultPort()) return connectSession(config.getHost()); else return connectSession(config.getHost(), config.getPort()); } private Session connectSession(String host, int port) { try { Connection cachedConnection = connectionCache.getConnection(host, port); return cachedConnection.authenticate(getAuthenticationContext()); } catch (IOException e) { throw new SmbConnectionException(e); } } private Session connectSession(String host) { return connectSession(host, SMBClient.DEFAULT_PORT); } private AuthenticationContext getAuthenticationContext() { String username = config.getUsername(); String domain = config.getDomain(); String password = config.getPassword(); if (username == null) throw new IllegalArgumentException("Username cannot be null!"); if (password == null) throw new IllegalArgumentException("Password cannot be null!"); return new AuthenticationContext(username, password.toCharArray(), domain); } private DfsResolutionResult resolvePath(Session session, SmbPath path) { if (isDfs()) { return connectDfsShare(session, path); } else { return connectNonDfsShare(session, path); } } private DfsResolutionResult connectDfsShare(Session session, SmbPath path) { DfsResolver resolver = new DfsResolver(); SmbPath resolvedPath = resolver.resolve(client, session, path); DiskShare share = getDfsShare(session, resolvedPath); return new DfsResolutionResult(share, resolvedPath); } private DfsResolutionResult connectNonDfsShare(Session session, SmbPath path) { DiskShare share = (DiskShare) session.connectShare(path.getShareName()); return new DfsResolutionResult(share, path); } private DiskShare getDfsShare(Session session, SmbPath resolvedPath) { if (isOnSameHost(session, resolvedPath)) { return (DiskShare) session.connectShare(resolvedPath.getShareName()); } else { Session newSession = connectSession(resolvedPath.getHostname()); return (DiskShare) newSession.connectShare(resolvedPath.getShareName()); } } private boolean isOnSameHost(Session session, SmbPath path) { return session.getConnection().getRemoteHostname().equals(path.getHostname()); } private long getFileSize() { return getShare().getFileInformation(getPath()).getStandardInformation().getEndOfFile(); } public void rename(String from, String to) { session = connectSession(); DfsResolutionResult resolvedFrom = resolvePlainPath(from); DfsResolutionResult resolvedTo = resolvePlainPath(to); if (!resolvedFrom.getSmbPath().isOnSameShare(resolvedTo.getSmbPath())) { throw new AttemptedRenameAcrossSharesException("Rename operation failed, " + from + " and " + to + " are on different shares!"); } DiskShare share = resolvedFrom.getDiskShare(); EnumSet renameAttributes = EnumSet.of(AccessMask.FILE_READ_ATTRIBUTES, AccessMask.DELETE, AccessMask.SYNCHRONIZE); try (File file = share.openFile(resolvedFrom.getSmbPath().getPath(), renameAttributes, null, SMB2ShareAccess.ALL, SMB2CreateDisposition.FILE_OPEN, null)) { file.rename(resolvedTo.getSmbPath().getPath()); } } public void storeFile(String path, InputStream inputStream) throws IOException { connect(path); try (File file = openForWrite(getShare(), getPath()); OutputStream outputStream = file.getOutputStream() ) { IOUtils.copy(inputStream, outputStream, bufferSize); } } public void appendFile(String path, InputStream inputStream) throws IOException { connect(path); try (File file = openForAppend(getShare(), getPath())) { long fileOffset = getFileSize(); int length; final byte[] buffer = new byte[4096]; final int EOF = -1; while (EOF != (length = inputStream.read(buffer))) { file.write(buffer, fileOffset, 0, length); fileOffset += length; } } } public List listFiles(String path) { connect(path); List files = new ArrayList<>(); for (FileIdBothDirectoryInformation f : getShare().list(getPath())) { boolean isDirectory = FileDirectoryAttributes.isDirectory(f); if (isDirectory) { //skip special directories . and .. if (f.getFileName().equals(CURRENT_DIRECTORY) || f.getFileName().equals(PARENT_DIRECTORY)) continue; } files.add(new SmbFile(isDirectory, f.getFileName(), f.getEndOfFile(), FileDirectoryAttributes.getLastModified(f), FileDirectoryAttributes.isArchive(f), FileDirectoryAttributes.isHidden(f), FileDirectoryAttributes.isReadOnly(f), FileDirectoryAttributes.isSystem(f))); } return files; } public void retrieveFile(String path, OutputStream os) throws IOException { connect(path); File f = openForRead(getShare(), getPath()); InputStream is = f.getInputStream(); IOHelper.copyAndCloseInput(is, os, bufferSize); } public boolean fileExists(String path) { connect(path); return getShare().fileExists(getPath()); } public void deleteFile(String path) { connect(path); if(getShare().fileExists(getPath())) { getShare().rm(getPath()); } } public boolean mkdirs(String directory) { connect(directory); Path path = Paths.get(getPath()); mkdirs(path); return true; } private void mkdirs(Path path) { Path parent = path.getParent(); if (parent != null && !getShare().folderExists(parent.toString())) mkdirs(path.getParent()); if (!getShare().folderExists(path.toString())) getShare().mkdir(path.toString()); } private static File openForWrite(DiskShare share, String name) { return share.openFile(name, EnumSet.of(AccessMask.GENERIC_WRITE), null, SMB2ShareAccess.ALL, SMB2CreateDisposition.FILE_CREATE, EnumSet.of(SMB2CreateOptions.FILE_SEQUENTIAL_ONLY)); } private static File openForAppend(DiskShare share, String name) { return share.openFile(name, EnumSet.of(AccessMask.GENERIC_WRITE), null, SMB2ShareAccess.ALL, SMB2CreateDisposition.FILE_OPEN_IF, EnumSet.of(SMB2CreateOptions.FILE_SEQUENTIAL_ONLY)); } private static File openForRead(DiskShare share, String name) { //NB https://msdn.microsoft.com/en-us/library/cc246502.aspx - SMB2 CREATE Request // ShareAccess.ALL means that other opens are allowed to read, but not write or delete the file return share.openFile(name, EnumSet.of(AccessMask.GENERIC_READ), null, SMB2ShareAccess.ALL, SMB2CreateDisposition.FILE_OPEN, null); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy