.NET File-System Extensions

A .NET file-system extension is a .NET assembly (usually a DLL) that contains a class that extends the class EnterpriseDT.Net.FtpServer.FileSystem.FileSystemAdapter. The assembly can be developed in C#, VB.NET or any other .NET language. If you don't already have Visual Studio then you can use one of Microsoft's free Visual Studio Express or Community products.

Creating a .NET file-system extension

General instructions on building CompleteFTP .NET extensions may be found here. In addition to the registration steps described in the general instructions, a .NET file-system extension must have a folder-type defined. The folder-type determines which extension should be used for a specific folder-type.

Once a new folder-type is added, it will be displayed in the list of folder-types that is displayed when a user adds a new folder to the virtual file-system.

File-system extension classes must extend EnterpriseDT.Net.FtpServer.FileSystem.FileSystemAdapter or one of its subclasses, e.g. WindowsAdapter, FolderAdapter or SpecialFolderAdapter. The base-class, FileSystemAdapter, is a concrete class but it disallows all operations, so some of its methods must therefore be overridden to make it functional. For example, if directory-listing and downloading are to be supported then GetFileInfos and GetReadStream must be implemented at a minimum. Many FTP clients do things like checking sizes and modification dates before downloading, so methods like GetFileLength and GetModifiedTime may also need to be implemented.

Example

Below is the source-code for a sample .NET file-system extension whose only function is to display file-names in upper case.

using System;
using System.Windows.Forms;
using EnterpriseDT.Net.FtpServer.Core;
using EnterpriseDT.Net.FtpServer.FileSystem;
using EnterpriseDT.Net.FtpServer.FileSystem.Windows;

namespace SampleExtensions
{
    public class UpperCaseFileSystem : FolderAdapter
    {
        public override VirtualFileInfo[] GetFileInfos(ISession session, IFileSystemNode node, string path, string pattern)
        {
            VirtualFileInfo[] files = base.GetFileInfos(session, node, path, pattern);
            foreach (VirtualFileInfo file in files)
                file.Name = file.Name.ToUpper();
            return files;
        }
    }

}

Adding UpperCaseFileSystem class into Extensions panel.

In the Folder panel, create a new folder with the new type which has been added above.

In the User panel, set the Home folder of the user to the newly created folder.

Login with File Zilla by using the user (which is set to the new type of folder). The login should be successful.

Then transfer a file which has a name which is not uppercase.

Check to see if the transfer was successful and that the name of the transferred file was changed to uppercase.

Creating an editor for a .NET file-system extension

A .NET file-system extension can optionally have a visual editor associated with it. This editor simply needs to pop up a form when a particular method is called. Extension editors must extend the class EnterpriseDT.Net.FtpServer.FileSystem.FileSystemAdapterEditor. They should be placed in the same assembly as the FileSystemAdapter extension itself. At a minimum they must override the IsUserConfigurable property and the ShowConfigDialog method. The IsUserConfigurable method should return true. The ShowConfigDialog takes an argument of type IFileSystemNode, which represents a folder in the virtual file-system. The job of the ShowConfigDialog method is to change the IFileSystemNode's Configuration property and return true if it has changed it.

Every method of FileSystemAdapter takes an argument of the same type, i.e. IFileSystemNode. Thus every method will have access to the user-configurable Configuration property. This is how, for example, each Windows folder in the virtual file-system is mapped to a specific Windows folder on the hard-disk.

Example

The following example opens a FolderBrowserDialog and allows the user to select a Windows path. Notice that the node.Configuration property is only set if the OK-button was pressed by the user.

using System;
using System.Windows.Forms;
using EnterpriseDT.Net.FtpServer.Core;
using EnterpriseDT.Net.FtpServer.FileSystem;
using EnterpriseDT.Net.FtpServer.FileSystem.Windows;

namespace SampleExtensions
{
    public class UpperCaseFileSystem : FolderAdapter
    {
        public override VirtualFileInfo[] GetFileInfos(ISession session, IFileSystemNode node, string path, string pattern)
        {
            VirtualFileInfo[] files = base.GetFileInfos(session, node, path, pattern);
            foreach (VirtualFileInfo file in files)
                file.Name = file.Name.ToUpper();
            return files;
        }
    }

    public class UpperCaseFileSystemEditor : FileSystemAdapterEditor
    {
        public virtual bool IsUserConfigurable
        {
            get { return true; }
        }
        public override bool ShowConfigDialog(IWin32Window parent, IFileSystemNode node)
        {
            FolderBrowserDialog browser = new FolderBrowserDialog();
            if (node.Configuration != null)
                browser.SelectedPath = node.Configuration;
            if (browser.ShowDialog(parent) == DialogResult.OK)
            {
                node.Configuration = browser.SelectedPath;
                return true;
            }
            else
                return false;
        }
    }
}

Note that after adding this extension into CompleteFTP, the user has to set the Editor class (including namespace) property of the extension in the CompleteFTP Manager to SampleExtensions.UpperCaseFileSystemEditor.

Create a new folder with the new type which has been added above, it will show the FolderBrowserDialog and allows the user to select a Windows path.

All of the remaining steps are the same as above.

Overview of File-System Adapter Classes

All file-system adapters must extend directly or indirectly from FileSystemAdapter. If you want your adapter to access the Windows file-system, then it's probably much easier to extend from one of its subclasses, such as FolderAdapter. For example, if you only want to implement some special mapping between the virtual file-system and the Windows file-system then you can simply override the GetWindowsPath method, which is responsible for mapping virtual paths into real paths.

FileSystemAdapter

namespace: EnterpriseDT.Net.FtpServer.FileSystem
editor: None

Every file or directory operation that the user initiates is done by means of a FileSystemAdapter. This includes uploading, downloading, renaming and deleting files, as well as creating, listing and deleting directories. Most of these operations are implemented by a single method. The class itself can be instantiated, but does nothing of value. It yields empty listings and allows no uploads, downloads, deletes, etc. Any method or all methods may be overridden in subclasses to add functionality. As stated previously, it's often desirable to extend FolderAdapter, since it already implements all methods required for interfacing with the Windows file-system, but may be modified as required.

Most methods of FileSystemAdapter take at least the following three arguments: session, node and path. The session contains information about the user's current session; the node has information about the folder in the virtual file system that the user is accessing; and the path is the path relative to the last virtual folder on the path. So if, for example, the user is accessing the file /a/b/c/d/e.txt, which is in a subfolder of the virtual directory, /a/b/c, then the path argument will be d/e.txt. The value of the property node.Configuration is the value set by the adapter editor (see above), when the virtual folder was created by the user.

WindowsAdapter extends FileSystemAdapter (abstract)

namespace: EnterpriseDT.Net.FtpServer.FileSystem.Windows
editor: None

Provides all the functionality necessary for CompleteFTP to access the Windows file-system except for the mapping of paths in the virtual file-system into real Windows paths. When it needs to map a path in the virtual file-system to a Windows path, it calls its own abstract method, GetWindowsPath. The main job of the subclasses of WindowsAdapter is to implement this method.

FolderAdapter extends WindowsArchiveAdapter

namespace: EnterpriseDT.Net.FtpServer.FileSystem.Windows
editor: FolderAdapterEditor

This is the main adapter for the Windows file-system. The editor sets the node.Configuration property to an absolute Windows path. The GetWindowsPath concatenates this absolute Windows path, and the path passed to the GetWindowsPath method, to return the full Windows path of the folder in the Windows file-system.

SpecialFolderAdapter extends WindowsArchiveAdapter

namespace: EnterpriseDT.Net.FtpServer.FileSystem.Windows
editor: SpecialFolderAdapterEditor

Adapter for a special Windows folder, such as the My Documents folder. The editor sets the node.Configuration property to a tag indicating which special folder is required. The GetWindowsPath returns the real Windows path of this folder, for the user whose session is being accessed.

Overview of Other Classes

ISession

namespace: EnterpriseDT.Net.FtpServer.Core

Provides information about the current user-session, including the name of the user and the IP address of the client.

IFileSystemNode

namespace: EnterpriseDT.Net.FtpServer.FileSystem

A file-system node is a folder in the virtual file-system. Every folder that you see in the virtual file-system view has a single file-system node associated with it. The most important property of IFileSystemNode is Configuration, which stores the path or other configuration that the visual editor sets when the user configured the folder in the CompleteFTP Manager.

VirtualFileInfo

namespace: EnterpriseDT.Net.FtpServer.FileSystem

Used to pass directory listing information from the FileSystemAdapter to CompleteFTP.

VirtualFileMode

namespace: EnterpriseDT.Net.FtpServer.FileSystem

Logging

The class EnterpriseDT.Util.Debug.Logger may be used to write messages to the CompleteFTP log. This can be very useful when debugging your adapter. To use this class, create a static instance of it in your adapter class and call it's Error, Warn or Debug method to write something to the CompleteFTP log file. For example:

using EnterpriseDT.Util.Debug;

public class UpperCaseFileNameAdapter : FolderAdapter
{
	private Logger log = Logger.GetLogger("UpperCaseFileNameAdapter");
	
	public override VirtualFileInfo[] GetFileInfos(ISession session, IFileSystemNode node, string path, string pattern)
	{
		log.Debug("Listing requested");
		...
	}
}

Class Reference

Class: FileSystemAdapter

bool DirectoryExists(ISession session, IFileSystemNode node, string path)
Returns true if a directory exists and false otherwise.
void CreateDirectory(ISession session, IFileSystemNode node, string path)
Create a directory at the given path.
VirtualFileInfo[] GetFileInfos(ISession session, IFileSystemNode node, string path, string pattern)
Return an array of VirtualFileInfo objects corresponding to the files in the given directory, that match the given pattern.
void DeleteDirectory(ISession session, IFileSystemNode node, string path)
Delete the given directory.
bool FileExists(ISession session, IFileSystemNode node, string path)
Returns true if a file exists and false otherwise.
void DeleteFile(ISession session, IFileSystemNode node, string path)
Delete the given file.
bool IsFileLengthKnown(ISession session, IFileSystemNode node, string path)
Returns true if the length of the given file is known and false otherwise.
long GetFileLength(ISession session, IFileSystemNode node, string path)
Returns the length of the given file in bytes.
DateTime GetModifiedTime(ISession session, IFileSystemNode node, string path)
Returns the time when the given file was last modified.
void SetModifiedTime(ISession session, IFileSystemNode node, string path, DateTime dateTime)
Sets the last-modified time of the given file.
Stream GetReadStream(ISession session, IFileSystemNode node, string path)
Returns a stream that may be used for reading the given file (used for downloads).
void OnReadStreamClosed(ISession session, IFileSystemNode node, string path, Stream stream)
Called when the read-stream (created by GetReadStream) is closed.
Stream GetWriteStream(ISession session, IFileSystemNode node, string path, VirtualFileMode mode)
Returns a stream that may be used for writing to the given file (used for downloads).
void OnWriteStreamClosed(ISession session, IFileSystemNode node, string path, Stream stream)
Called when the write-stream (created by GetWriteStream) is closed.
bool MoveFile(ISession session, IFileSystemNode fromNode, string fromPath, FileSystemAdapter toAdapter, IFileSystemNode toNode, string toPath)
Move the given file from one location in the virtual file-system (defined by fromNode and fromPath) to another location (defined by toAdapter, toNode and toPath). For simple file renaming, the fromNode will be the same as the toNode and the toAdapter will be the 'this' adapter.
string GetAdapterFilePath(ISession session, IFileSystemNode node, string path)
void Initialize(IPlugInInfo info)
Called when the extension is first created.
void Dispose()
Called when the extension is disposed of.