chrismair | 00dc7bd | 2014-05-11 21:21:28 +0000 | [diff] [blame] | 1 | --------------------------------------------------
|
| 2 | FakeFtpServer Filesystems
|
| 3 | --------------------------------------------------
|
| 4 |
|
| 5 | FakeFtpServer Filesystems
|
| 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 7 |
|
| 8 | <<FakeFtpServer>> provides a simulated server file system, including support for file and directory permissions
|
| 9 | and owner and group authorization based on Unix. This file system can be populated at startup (or thereafter) with
|
| 10 | directories and files (including arbitrary content) to be retrieved by an FTP client. Any files sent to the server
|
| 11 | by an FTP client exist within that file system as well, and can be accessed through the file system API, or
|
| 12 | can even be subsequently retrieved by an FTP client.
|
| 13 |
|
| 14 | The filesystem abstraction is accessed through the <<<FileSystem>>> interface in the
|
| 15 | <<<org.mockftpserver.fake.filesystem>>> package. Two implementations of this interface are provided:
|
| 16 | <<<WindowsFakeFileSystem>>> and <<<UnixFakeFileSystem>>>. They both manage the files and directories in memory,
|
| 17 | simulating a real file system. You are also free to implement your own <<<FileSystem>>> implementation.
|
| 18 |
|
| 19 | Note that both <<<WindowsFakeFileSystem>>> and <<<UnixFakeFileSystem>>> are <virtual> file systems, and do
|
| 20 | not depend on the <real> operating systems or file systems on which <<FakeFtpServer>> is running. In other
|
| 21 | words, you can configure and run a <<FakeFtpServer>> with a <<<WindowsFakeFileSystem>>> on top of a <real>
|
| 22 | Unix system, or run a <<FakeFtpServer>> with a <<<UnixFakeFileSystem>>> on top of a <real> Windows system.
|
| 23 |
|
| 24 | See the javadoc for these classes for more information.
|
| 25 |
|
| 26 |
|
| 27 | * WindowsFakeFileSystem
|
| 28 | ~~~~~~~~~~~~~~~~~~~~~~~
|
| 29 |
|
| 30 | <<WindowsFakeFileSystem>> is an implementation of the <<<FileSystem>>> interface that simulates a Microsoft
|
| 31 | Windows file system. The rules for file and directory names include:
|
| 32 |
|
| 33 | * Filenames are case-insensitive
|
| 34 |
|
| 35 | * Either forward slashes (/) or backward slashes (\) are valid path separators (but are normalized to '\')
|
| 36 |
|
| 37 | * An absolute path starts with a drive specifier (e.g. 'a:' or 'c:') followed by '\' or '/',
|
| 38 | or else it starts with "\\"</li>
|
| 39 |
|
| 40 |
|
| 41 | * UnixFakeFileSystem
|
| 42 | ~~~~~~~~~~~~~~~~~~~~
|
| 43 |
|
| 44 | <<UnixFakeFileSystem>> is an implementation of the <<<FileSystem>>> interface that simulates a Unix
|
| 45 | file system. The rules for file and directory names include:
|
| 46 |
|
| 47 | * Filenames are case-sensitive
|
| 48 |
|
| 49 | * Forward slashes (/) are the only valid path separators
|
| 50 |
|
| 51 |
|
| 52 | * WindowsFakeFileSystem and UnixFakeFileSystem: Common Behavior and Configuration
|
| 53 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 54 |
|
| 55 | Both <<<WindowsFakeFileSystem>>> and <<<UnixFakeFileSystem>>> are subclasses of <<<AbstractFakeFileSystem>>>. They
|
| 56 | manage the files and directories in memory, simulating a real file system.
|
| 57 |
|
| 58 | If the <createParentDirectoriesAutomatically> property is set to <true>,
|
| 59 | then creating a directory or file will automatically create any parent directories (recursively)
|
| 60 | that do not already exist. If <false>, then creating a directory or file throws an
|
| 61 | exception if its parent directory does not exist. This value defaults to <true>.
|
| 62 |
|
| 63 | The <directoryListingFormatter> property holds an instance of <<DirectoryListingFormatter>>,
|
| 64 | used by the <formatDirectoryListing> method to format directory listings in a
|
| 65 | filesystem-specific manner. This property is initialized by concrete subclasses.
|
| 66 |
|
| 67 |
|
| 68 | * File Permissions, Owners and Groups
|
| 69 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 70 |
|
| 71 | Each <file> or <directory> entry within a <<<FileSystem>>> has associated <owner>, <group> and <permissions>
|
| 72 | attributes. All of these attributes are optional. If none are specified for a file or directory, then full
|
| 73 | access by all users is the default.
|
| 74 |
|
| 75 | If, however, these values are specified for a filesystem entry, then they affect whether a file can be created,
|
| 76 | read, written or deleted, and whether a directory can be created, listed or deleted.
|
| 77 |
|
| 78 | This approach for access control is conceptually (and somewhat loosely) based on the Unix file system, but
|
| 79 | don't expect a comprehensive implementation fully matching Unix's capabilities.
|
| 80 |
|
| 81 |
|
| 82 | ** Permissions
|
| 83 | ~~~~~~~~~~~~~~
|
| 84 |
|
| 85 | The permissions for a file or directory entry in the filesystem are represented by a 9-character string of
|
| 86 | the form "rwxrwxrwx", consisting of three "rwx" triples. Each triple indicates the READ ("r"), WRITE ("w") and
|
| 87 | EXECUTE ("x") permissions for a specific set of users. Each position can alternatively contain a "-" to
|
| 88 | indicate no READ/WRITE/EXECUTE access, depending on its position.
|
| 89 |
|
| 90 | The first "rwx" triple indicates the READ, WRITE and EXECUTE permissions for the owner of the file. The
|
| 91 | second triple indicates the permissions for the group associated with the file. The third triple
|
| 92 | indicates the permissions for the rest of the world.
|
| 93 |
|
| 94 | For example, the permissions string "rwx--xrw-" is interpreted to mean that users have READ/WRITE/EXECUTE access,
|
| 95 | the group has only EXECUTE, and the world has only READ and WRITE.
|
| 96 |
|
| 97 | There are plenty of good tutorials and references for understanding Unix file permissions, including
|
| 98 | {{{http://www.dartmouth.edu/~rc/help/faq/permissions.html}this one}}.
|
| 99 |
|
| 100 | The <<<Permissions>>> class represents and encapsulates the read/write/execute permissions for a file or
|
| 101 | directory. Its constructor takes a 9-character "rwx" String as described above.
|
| 102 |
|
| 103 | The <<<AbstractFileSystemEntry>>> contains a <permissions> attribute, so that every file and directory in the
|
| 104 | file system can be assigned a unique set of permissions from a <<<Permissions>>> object. There is also a
|
| 105 | <<<setPermissionsFromString()>>> convenience setter that allows setting the permissions directly from a String.
|
| 106 |
|
| 107 |
|
| 108 | ** FileSystem Access Rules
|
| 109 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 110 |
|
| 111 | *** When Are READ, WRITE or EXECUTE Access Required?
|
| 112 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 113 |
|
| 114 | If the <permissions> are configured for a file or directory within the <<<FileSystem>>>, then
|
| 115 | those permissions affect whether and how that file/directory can be accessed.
|
| 116 | Here are the rules for applying permissions for file access:
|
| 117 |
|
| 118 | *------------------------*-------------------------------------------------------------------*
|
| 119 | | <<Operation>> | <<Required Permissions>> |
|
| 120 | *------------------------*-------------------------------------------------------------------*
|
| 121 | | Create a new file | EXECUTE access to the directory and WRITE access to the directory |
|
| 122 | *------------------------*-------------------------------------------------------------------*
|
| 123 | | Read a file | EXECUTE access to the directory and READ access to the file |
|
| 124 | *------------------------*-------------------------------------------------------------------*
|
| 125 | | Write a file | EXECUTE access to the directory and WRITE access to the file |
|
| 126 | *------------------------*-------------------------------------------------------------------*
|
| 127 | | Delete a file | WRITE access to the directory |
|
| 128 | *------------------------*-------------------------------------------------------------------*
|
| 129 | | Rename a file | READ access to the FROM file and WRITE access to the directory |
|
| 130 | *------------------------*-------------------------------------------------------------------*
|
| 131 | | Create a directory | WRITE and EXECUTE acccess to the parent directory |
|
| 132 | *------------------------*-------------------------------------------------------------------*
|
| 133 | | List a directory | READ acccess to the directory/file |
|
| 134 | *------------------------*-------------------------------------------------------------------*
|
| 135 | | CD to a directory | EXECUTE acccess to the directory |
|
| 136 | *------------------------*-------------------------------------------------------------------*
|
| 137 | | Delete a directory | WRITE acccess to the parent directory |
|
| 138 | *------------------------*-------------------------------------------------------------------*
|
| 139 |
|
| 140 | *** How Do Owner and Group Affect Access?
|
| 141 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 142 |
|
| 143 | Each file and directory in the filesystem (subclass of <<<AbstractFileSystemEntry>>>) contains <owner>
|
| 144 | and <group> attributes. These attributes are optional.
|
| 145 |
|
| 146 | If the <owner> is configured for a file/directory, AND the <permissions> are configured as well,
|
| 147 | then the <<owner>> triple from the <permissions> are applied if and only if the <<<UserAccount>>> for the
|
| 148 | currently logged in FTP user (client) matches the <owner> configured for the file/directory.
|
| 149 |
|
| 150 | Similarly, if the <group> is configured for a file/directory, AND the <permissions> are configured as well,
|
| 151 | then the <<group>> triple from the <permissions> are applied if and only if <groups> configured for the
|
| 152 | <<<UserAccount>>> for the currently logged in FTP user (client) contain the <group> configured for the file/directory.
|
| 153 |
|
| 154 | Otherwise, the <<world>> triple from the <permissions> are applied.
|
| 155 |
|
| 156 | * Example Code
|
| 157 | ~~~~~~~~~~~~~~
|
| 158 |
|
| 159 | This example illustrates setting the permissions, owner and group for directories and files within the
|
| 160 | <<<FakeFtpServer>>> filesystem. In this case, the filesystem is an instance of <<<WindowsFakeFileSystem>>>,
|
| 161 | but the code would be almost exactly the same for <<<UnixFakeFileSystem>>> as well.
|
| 162 |
|
| 163 | +------------------------------------------------------------------------------
|
| 164 | final String USER1 = "joe";
|
| 165 | final String USER2 = "mary";
|
| 166 | final String GROUP = "dev";
|
| 167 | final String CONTENTS = "abcdef 1234567890";
|
| 168 |
|
| 169 | FileSystem fileSystem = new WindowsFakeFileSystem();
|
| 170 | DirectoryEntry directoryEntry1 = new DirectoryEntry("c:\\");
|
| 171 | directoryEntry1.setPermissions(new Permissions("rwxrwx---"));
|
| 172 | directoryEntry1.setOwner(USER1);
|
| 173 | directoryEntry1.setGroup(GROUP);
|
| 174 |
|
| 175 | DirectoryEntry directoryEntry2 = new DirectoryEntry("c:\\data");
|
| 176 | directoryEntry2.setPermissions(Permissions.ALL);
|
| 177 | directoryEntry2.setOwner(USER1);
|
| 178 | directoryEntry2.setGroup(GROUP);
|
| 179 |
|
| 180 | FileEntry fileEntry1 = new FileEntry("c:\\data\\file1.txt", CONTENTS);
|
| 181 | fileEntry1.setPermissionsFromString("rw-rw-rw-");
|
| 182 | fileEntry1.setOwner(USER1);
|
| 183 | fileEntry1.setGroup(GROUP);
|
| 184 |
|
| 185 | FileEntry fileEntry2 = new FileEntry("c:\\data\\run.exe");
|
| 186 | fileEntry2.setPermissionsFromString("rwxrwx---");
|
| 187 | fileEntry2.setOwner(USER2);
|
| 188 | fileEntry2.setGroup(GROUP);
|
| 189 |
|
| 190 | fileSystem.add(directoryEntry1);
|
| 191 | fileSystem.add(directoryEntry2);
|
| 192 | fileSystem.add(fileEntry1);
|
| 193 | fileSystem.add(fileEntry2);
|
| 194 |
|
| 195 | FakeFtpServer fakeFtpServer = new FakeFtpServer();
|
| 196 | fakeFtpServer.setFileSystem(fileSystem);
|
| 197 | +------------------------------------------------------------------------------
|
| 198 |
|
| 199 | Things to note about the above example:
|
| 200 |
|
| 201 | * The <<<FakeFtpServer>>> instance is configured with a <<<WindowsFakeFileSystem>>> and a "c:\" root
|
| 202 | directory with a "data" sub-directory containing two files. Permissions and owner/group are specified for
|
| 203 | both directories and both files.
|
| 204 |
|
| 205 | * The permissions for the directories are specified using the "permissions" setter, which takes an
|
| 206 | instance of the <<<Permissions>>> class. The permissions for both files are specified using the
|
| 207 | "permissionsFromString" shortcut method. Either way is fine -- use whichever method you prefer on
|
| 208 | both files and directories.
|
| 209 |
|
| 210 | []
|
| 211 |
|
| 212 | When you want to retrieve and/or verify the contents of the <<<FakeFtpServer>>> filesystem, you can use
|
| 213 | the <<<FileSystem#getEntry(String path)>>> method, as shown in the following code.
|
| 214 |
|
| 215 | +------------------------------------------------------------------------------
|
| 216 | DirectoryEntry dirEntry = (DirectoryEntry)fileSystem.getEntry("c:/data");
|
| 217 |
|
| 218 | FileEntry fileEntry = (FileEntry)fileSystem.getEntry("c:/data/file1.txt");
|
| 219 |
|
| 220 | FileEntry newFileEntry = (FileEntry)fileSystem.getEntry("c:/data/new.txt");
|
| 221 | InputStream inputStream = newFileEntry.createInputStream();
|
| 222 | // read the file contents using inputStream
|
| 223 | +------------------------------------------------------------------------------
|
| 224 |
|
| 225 | See the javadoc for <<<FileSystem>>>, <<<FileEntry>>> and <<<DirectoryEntry>>> for more information
|
| 226 | on the methods available.
|
| 227 |
|
| 228 |
|
| 229 | ** Example Using Spring Configuration
|
| 230 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 231 |
|
| 232 | See the {{{./fakeftpserver-getting-started.html#Spring}FakeFtpServer Getting Started - Spring Configuration}}
|
| 233 | for an example of how to configure a <<<FakeFtpServer>>> instance and associated filesystem in the
|
| 234 | {{{http://www.springframework.org/}Spring Framework}}.
|
| 235 | |