+1 vote
by (190 points)
edited by

my client has a list of newsletters etc whose name and physical locations are in a database. the don't want their clients to connect direct to the database to get these files. They already have an SFTP portal system based on the REBEX components.
Is there a way to override the "List" command or write an extension to achieve this?

Applies to: Rebex SFTP, File Server
by (190 points)
Thanks Tomas for the quick reply.  As a newish C# programmer, I will have to have a think about how to implement your answer. It looks good though.
by (58.9k points)
You're welcome. Let us know if you come something that would need clarification.

2 Answers

+1 vote
by (148k points)
 
Best answer

We added a powerful and simple-to-use custom file system API to Rebex File Server 2017 R4.

For additional information and sample code, check out the Virtual file systems page.

The File Server package also includes a sample app that shows how to implement custom file system providers.

0 votes
by (58.9k points)
edited by

Update: Rebex File Server 2017 R4 adds virtual file systems support. See the latest answer for details.


Although virtual file systems are not supported yet, Rebex File Server internals were designed with this scenario in mind and we plan to add a simple-to-use high-level API for this soon.

In the meantime, you can try Rebex File Server Beta with proof-of-concept IFilesystem API.

Customers with active support contract - write us an email to support@rebex.net to receive the full version of the beta. Please note that the API will most likely change for the official release.

To get started, just try the following code. It implements a FileServerEx class that inherits from FileServer, but wraps its filesystem object in a custom class that can be customized to do something else. For example, the OpenFile method can be modified to return a custom IHandle instead of calling _inner.OpenFile, and other methods that take IHandle can be enhanced to handle both custom and built-in IHandles. In your scenario, you will probably want to ignore the built-in IFilesystem implementations and write a custom filesystem that will enable you to open the virtual directory from database and then let users download the newsletter files that are physically located on the disk via the built-in IFileSystem implementation.

public class FileServerExt : FileServer
{
    private class FilesystemWrapper : IFilesystem
    {
        private readonly IFilesystem _inner;
        public FilesystemWrapper(IFilesystem inner)
        {
            _inner = inner;
        }

        void IFilesystem.Close(IHandle handle)
        {
            _inner.Close(handle);
        }

        void IFilesystem.CreateDirectory(string path)
        {
            _inner.CreateDirectory(path);
        }

        void IFilesystem.DeleteDirectory(string path)
        {
            _inner.DeleteDirectory(path);
        }

        void IFilesystem.DeleteFile(string path)
        {
            _inner.DeleteFile(path);
        }

        FilesystemInfo IFilesystem.GetFilesystemInfo()
        {
            return _inner.GetFilesystemInfo();
        }

        ItemInfo IFilesystem.GetItemInfo(string path)
        {
            return _inner.GetItemInfo(path);
        }

        string IFilesystem.Normalize(string absolutePath)
        {
            return _inner.Normalize(absolutePath);
        }

        IHandle IFilesystem.OpenDirectory(string path, string mask)
        {
            return _inner.OpenDirectory(path, mask);
        }

        IHandle IFilesystem.OpenFile(string path, FileOpenMode openMode, FileAccessMode accessMode)
        {
            return _inner.OpenFile(path, openMode, accessMode);
        }

        int IFilesystem.Read(IHandle handle, byte[] buffer, int offset, int count)
        {
            return _inner.Read(handle, buffer, offset, count);
        }

        ItemInfo IFilesystem.ReadNextItem(IHandle handle)
        {
            return _inner.ReadNextItem(handle);
        }

        void IFilesystem.Rename(string sourcePath, string targetPath)
        {
            _inner.Rename(sourcePath, targetPath);
        }

        string IFilesystem.ResolvePath(string path, string relativePath)
        {
            return _inner.ResolvePath(path, relativePath);
        }

        long IFilesystem.Seek(IHandle handle, FileSeekOrigin origin, long offset)
        {
            return _inner.Seek(handle, origin, offset);
        }

        void IFilesystem.SetItemInfo(string path, ItemInfo info)
        {
            _inner.SetItemInfo(path, info);
        }

        void IFilesystem.SetItemInfo(IHandle handle, ItemInfo info)
        {
            _inner.SetItemInfo(handle, info);
        }

        void IFilesystem.Write(IHandle handle, byte[] buffer, int offset, int count)
        {
            _inner.Write(handle, buffer, offset, count);
        }
    }

    protected override IFilesystem GetFilesystem(ServerUser user)
    {
        IFilesystem inner = base.GetFilesystem(user);
        IFilesystem outer = new FilesystemWrapper(inner);
        return outer;
    }
}

Please note that when using the FileServerExt class intead of FileServer class, user’s virtualRootPath still applies, making it possible for different users to access different parts of the custom filesystem.

...