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 <gh...@commercehub.com> 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:john.hart...@gmail.com]
> Sent: Wednesday, October 16, 2013 9:58 AM
> To: ftpserver-users@mina.apache.org
> 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 <gh...@commercehub.com<mailto:
> gh...@commercehub.com>> 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"

Reply via email to