It looks like the mailing list strips attachments. Here's the source,
pasted in:
Unfortunately there are some imports that I can't provide you, but you
should be able to knock up a substitute.
-------------------------------------
package com.example.apachesftp.filesystem.delegating;
import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
import org.apache.sshd.common.Session;
import org.apache.sshd.server.FileSystemFactory;
import org.apache.sshd.server.FileSystemView;
public class DelegatingFilesystemFactory implements FileSystemFactory {
Map<String, FileSystemFactory> delegateFactories = new TreeMap<String,
FileSystemFactory>();
@Override
public FileSystemView createFileSystemView(final Session session)
throws IOException {
Map<String, FileSystemView> delegates = new TreeMap<String,
FileSystemView>();
for (Entry<String, FileSystemFactory> entry : delegateFactories
.entrySet()) {
delegates.put(entry.getKey(),
entry.getValue().createFileSystemView(session));
}
return new DelegatingFilesystemView(session, delegates);
}
/**
* Provides a set of FileSystemFactories from which delegate
FileSystemViews
* are created.
*
* @param delegateFactories
* A map. The keys are the names of the "directories" used for
* these delegates; the values are the FileSystemFactories.
*/
public void setDelegateFactories(
final Map<String, FileSystemFactory> delegateFactories) {
this.delegateFactories = delegateFactories;
}
}
---------------------------------------
package com.example.apachesftp.filesystem.delegating;
import java.io.*;
import java.util.*;
import org.apache.sshd.server.FileSystemView;
import org.apache.sshd.server.SshFile;
import com.example.apachesftp.filesystem.*;
public class DelegatingSshFile implements DelegatableSshDirectory {
public enum Disposition {
ROOT_OF_EVERYTHING, ROOT_OF_DELEGATE, IN_DELEGATE
}
private final String root;
private final SshFile delegate;
private final Map<String, FileSystemView> delegates;
private String alias = null;
private DelegatableSshDirectory parent = this;
/*
* Some notes.
*
* If absolute path is empty or "/" then we are the root of the
delegating
* filesystem.
*
* If absolute path is exactly one element long, then we are at the root
of a
* delegate
*
* If the absolute path is 2 elements or more, then we are deeper into a
* delegate.
*/
public DelegatingSshFile(String path,
final Map<String, FileSystemView> delegates) {
if (path.equals(".")) {
path = "/";
}
String[] parts = PathUtil.headAndTail(path);
this.root = parts[0];
this.delegates = delegates;
FileSystemView delegateFSV = delegates.get(root);
if (null != delegateFSV) {
this.delegate = delegateFSV.getFile(parts[1]);
} else {
this.delegate = new NonExistantSshFile(parts[1]);
}
}
public DelegatingSshFile(final String root, final SshFile delegate,
final Map<String, FileSystemView> delegates) {
this.root = root;
this.delegate = delegate;
this.delegates = delegates;
}
public Disposition getDisposition() {
if (PathUtil.isBottom(root)) {
return Disposition.ROOT_OF_EVERYTHING;
}
if (delegate instanceof NonExistantSshFile) {
if (PathUtil.isBottom(delegate.getAbsolutePath())) {
return Disposition.ROOT_OF_EVERYTHING;
} else {
return Disposition.IN_DELEGATE;
}
}
if (PathUtil.isBottom(delegate.getAbsolutePath())) {
return Disposition.ROOT_OF_DELEGATE;
}
// else
return Disposition.IN_DELEGATE;
}
@Override
public String getAbsolutePath() {
if (PathUtil.isBottom(root)) {
return "/";
} else {
return PathUtil.joinPaths(root, delegate.getAbsolutePath());
}
}
@Override
public String getName() {
if(alias != null) {
return alias;
} else {
return getOriginalName();
}
}
private String getOriginalName() {
String name = delegate.getName();
if (PathUtil.isBottom(name)) {
name = root;
}
name = PathUtil.deSlashFront(name);
if (name.equals("")) {
name = "/";
}
return name;
}
@Override
public boolean isDirectory() {
switch (getDisposition()) {
case ROOT_OF_EVERYTHING:
return true;
default:
return delegate.isDirectory();
}
}
@Override
public boolean isFile() {
switch (getDisposition()) {
case ROOT_OF_EVERYTHING:
return false;
default:
return delegate.isFile();
}
}
@Override
public boolean doesExist() {
switch (getDisposition()) {
case ROOT_OF_EVERYTHING:
if(root.equals("")) {
return true;
} else {
return delegates.keySet().contains(root);
}
default:
return delegate.doesExist();
}
}
@Override
public boolean isReadable() {
switch (getDisposition()) {
case ROOT_OF_EVERYTHING:
return true;
default:
return delegate.isReadable();
}
}
@Override
public boolean isWritable() {
switch (getDisposition()) {
case ROOT_OF_EVERYTHING:
return false;
default:
return delegate.isWritable();
}
}
@Override
public boolean isExecutable() {
switch (getDisposition()) {
case ROOT_OF_EVERYTHING:
return true;
default:
return delegate.isExecutable();
}
}
@Override
public boolean isRemovable() {
return delegate.isRemovable();
}
@Override
public SshFile getParentFile() {
switch (getDisposition()) {
case ROOT_OF_EVERYTHING:
return this;
case ROOT_OF_DELEGATE:
return new DelegatingSshFile("/", delegates);
default:
return new DelegatingSshFile(root, delegate.getParentFile(),
delegates);
}
}
@Override
public long getLastModified() {
switch (getDisposition()) {
case ROOT_OF_EVERYTHING:
return 0;
default:
return delegate.getLastModified();
}
}
@Override
public boolean setLastModified(final long time) {
switch (getDisposition()) {
case ROOT_OF_EVERYTHING:
return false;
default:
return delegate.setLastModified(time);
}
}
@Override
public long getSize() {
switch (getDisposition()) {
case ROOT_OF_EVERYTHING:
return delegates.size(); // plus . and ..
default:
return delegate.getSize();
}
}
@Override
public boolean mkdir() {
switch (getDisposition()) {
case ROOT_OF_EVERYTHING:
return false;
default:
return delegate.mkdir();
}
}
@Override
public boolean delete() {
switch (getDisposition()) {
case ROOT_OF_EVERYTHING:
return false;
default:
return delegate.delete();
}
}
@Override
public boolean create() throws IOException {
switch (getDisposition()) {
case ROOT_OF_EVERYTHING:
return false;
default:
return delegate.create();
}
}
@Override
public void truncate() throws IOException {
}
@Override
public boolean move(final SshFile destination) {
switch (getDisposition()) {
case ROOT_OF_EVERYTHING:
return false;
default:
return delegate.move(destination);
}
}
@Override
public List<SshFile> listSshFiles() {
switch (getDisposition()) {
case ROOT_OF_EVERYTHING:
return listDelegates();
default:
List<SshFile> files = delegate.listSshFiles();
return delegatify(files);
}
}
private List<SshFile> listDelegates() {
List<SshFile> l = new LinkedList<SshFile>();
l.add(copyWithAlias("."));
l.add(parent.copyWithAlias(".."));
Set<String> keys = this.delegates.keySet();
for (String key : keys) {
l.add(new DelegatingSshFile(key, delegates));
}
return l;
}
private List<SshFile> delegatify(final List<SshFile> plainFiles) {
List<SshFile> l = new LinkedList<SshFile>();
if(null != plainFiles) {
for (SshFile f : plainFiles) {
l.add(new DelegatingSshFile(root, f, delegates));
}
}
return l;
}
@Override
public OutputStream createOutputStream(final long offset) throws
IOException {
switch (getDisposition()) {
case ROOT_OF_EVERYTHING:
return null;
default:
return delegate.createOutputStream(offset);
}
}
@Override
public InputStream createInputStream(final long offset) throws
IOException {
return delegate.createInputStream(offset);
}
@Override
public void handleClose() throws IOException {
switch (getDisposition()) {
case ROOT_OF_EVERYTHING:
break;
default:
delegate.handleClose();
}
}
@Override
public void setAlias(String alias) {
this.alias = alias;
}
@Override
public DelegatingSshFile copyWithAlias(String alias) {
DelegatingSshFile copy = new DelegatingSshFile(root,delegate,delegates);
copy.setAlias(alias);
return copy;
}
@Override
public void setParent(DelegatableSshDirectory parent) {
this.parent = parent;
}
@Override
public String getOwner() {
switch (getDisposition()) {
case ROOT_OF_EVERYTHING:
return "system";
default:
return delegate.getOwner();
}
}
public SshFile getDelegate() {
return delegate;
}
}
------------------------
package com.example.apachesftp.filesystem.delegating;
import java.util.Map;
import org.apache.sshd.common.Session;
import org.apache.sshd.server.FileSystemView;
import org.apache.sshd.server.SshFile;
public class DelegatingFilesystemView implements FileSystemView {
private Map<String, FileSystemView> delegates;
public DelegatingFilesystemView(final Session session,
final Map<String, FileSystemView> delegates) {
setDelegates(delegates);
}
public void setDelegates(final Map<String, FileSystemView> delegates) {
this.delegates = delegates;
}
@Override
public SshFile getFile(final String path) {
DelegatingSshFile f = new DelegatingSshFile(
PathUtil.cleanDots(path), delegates);
if(f instanceof DelegatableSshDirectory) {
DelegatingSshFile root = new DelegatingSshFile("/", delegates);
f.setParent(root);
}
return f;
}
@Override
public SshFile getFile(final SshFile baseDir, final String file) {
String fullPath = PathUtil.joinPaths(baseDir.getAbsolutePath(), file);
return getFile(fullPath);
}
}
On 16 October 2013 15:20, Gentian Hila <[email protected]> wrote:
> Thank you very much,
>
> I will take a look around the interfaces you suggest. I did not get any
> attached files though.
>
>
> Genti
>
> From: John Hartnup [mailto:[email protected]]
> Sent: Wednesday, October 16, 2013 9:58 AM
> To: [email protected]
> Subject: Re: directory structure permissions & account locking
>
> The answer to any question like this is to customise the Filesystem
> classes to do what you want.
>
> I've attached some Java files (not warrantied for any particular purpose)
> for "DelegatingFilesystem" -- you can use one of these as the top of your
> filesystem hierarchy, with real, separately configured, filesystems as
> delegates, which appear as subdirectories.
>
> To grok these, you'll need to grok the FilesystemView,
> FilesystemViewFactory and SshFile interfaces - read the interfaces and
> they'll probably make sense.
>
>
>
> On 16 October 2013 14:50, Gentian Hila <[email protected]<mailto:
> [email protected]>> wrote:
> We have a use case where we would want to have two subdirectories under
> the user home directory incoming and outgoing. Each of them would have a
> hierarchical path.
>
> However, we want:
>
> User have read-only permissions for the outgoing directory and its
> children.
> User have read-write permissions for the incoming directory and its
> children.
> Users cannot change the structure of the directories ( I think we can
> achieve that by disabling MKDIR and RMD).
> Users cannot delete a file ( we can achieve that by disabling DELE
> command).
>
> However I do not see a way how to apply different permissions to different
> folders either through configuration or through extending the API source
> code yet.
>
> Is this possible at all? Has anybody attempted to do this?
>
>
>
>
> We also have a use case that basically requires that we lock an account
> after several failed logins. I did not see a mechanism for account locking
> and unlocking when this happens?
>
> Am I missing something?
>
>
> Genti
>
>
>
> --
> "There is no way to peace; peace is the way"
>
--
"There is no way to peace; peace is the way"