/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.sshd.server.subsystem.sftp;
import java.io.IOException;
import java.io.StreamCorruptedException;
import java.nio.channels.Channel;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.attribute.FileAttribute;
import java.util.Set;
import org.apache.sshd.server.session.ServerSession;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public interface SftpFileSystemAccessor {
SftpFileSystemAccessor DEFAULT = new SftpFileSystemAccessor() {
@Override
public String toString() {
return SftpFileSystemAccessor.class.getSimpleName() + "[DEFAULT]";
}
};
/**
* Called whenever a new file is opened
*
* @param session The {@link ServerSession} through which the request was received
* @param subsystem The SFTP subsystem instance that manages the session
* @param file The requested <U>local</U> file {@link Path}
* @param handle The assigned file handle through which the remote peer references this file.
* May be {@code null}/empty if the request is due to some internal functionality
* instead of due to peer requesting a handle to a file.
* @param options The requested {@link OpenOption}s
* @param attrs The requested {@link FileAttribute}s
* @return The opened {@link SeekableByteChannel}
* @throws IOException If failed to open
*/
default SeekableByteChannel openFile(
ServerSession session, SftpEventListenerManager subsystem,
Path file, String handle, Set<? extends OpenOption> options, FileAttribute<?>... attrs)
throws IOException {
return FileChannel.open(file, options, attrs);
}
/**
* Called when locking a section of a file is requested
*
* @param session The {@link ServerSession} through which the request was received
* @param subsystem The SFTP subsystem instance that manages the session
* @param file The requested <U>local</U> file {@link Path}
* @param handle The assigned file handle through which the remote peer references this file
* @param channel The original {@link Channel} that was returned by {@link #openFile(ServerSession, SftpEventListenerManager, Path, String, Set, FileAttribute...)}
* @param position The position at which the locked region is to start - must be non-negative
* @param size The size of the locked region; must be non-negative, and the sum
* <tt>position</tt> + <tt>size</tt> must be non-negative
* @param shared {@code true} to request a shared lock, {@code false} to request an exclusive lock
* @return A lock object representing the newly-acquired lock, or {@code null}
* if the lock could not be acquired because another program holds an overlapping lock
* @throws IOException If failed to honor the request
* @see FileChannel#tryLock(long, long, boolean)
*/
default FileLock tryLock(ServerSession session, SftpEventListenerManager subsystem,
Path file, String handle, Channel channel, long position, long size, boolean shared)
throws IOException {
if (!(channel instanceof FileChannel)) {
throw new StreamCorruptedException("Non file channel to lock: " + channel);
}
return ((FileChannel) channel).lock(position, size, shared);
}
/**
* Called when file meta-data re-synchronization is required
*
* @param session The {@link ServerSession} through which the request was received
* @param subsystem The SFTP subsystem instance that manages the session
* @param file The requested <U>local</U> file {@link Path}
* @param handle The assigned file handle through which the remote peer references this file
* @param channel The original {@link Channel} that was returned by {@link #openFile(ServerSession, SftpEventListenerManager, Path, String, Set, FileAttribute...)}
* @throws IOException If failed to execute the request
* @see FileChannel#force(boolean)
* @see <A HREF="https://github.com/openssh/openssh-portable/blob/master/PROTOCOL">OpenSSH - section 10</A>
*/
default void syncFileData(ServerSession session, SftpEventListenerManager subsystem,
Path file, String handle, Channel channel)
throws IOException {
if (!(channel instanceof FileChannel)) {
throw new StreamCorruptedException("Non file channel to sync: " + channel);
}
((FileChannel) channel).force(true);
}
/**
* Called when a new directory stream is requested
*
* @param session The {@link ServerSession} through which the request was received
* @param subsystem The SFTP subsystem instance that manages the session
* @param dir The requested <U>local</U> directory
* @param handle The assigned directory handle through which the remote peer references this directory
* @return The opened {@link DirectoryStream}
* @throws IOException If failed to open
*/
default DirectoryStream<Path> openDirectory(
ServerSession session, SftpEventListenerManager subsystem, Path dir, String handle)
throws IOException {
return Files.newDirectoryStream(dir);
}
}