1 /* 2 * Copyright (C) 2005-2015 Schlichtherle IT Services. 3 * All rights reserved. Use is subject to license terms. 4 */ 5 package net.java.truevfs.kernel.spec; 6 7 import java.io.IOException; 8 import java.lang.annotation.Inherited; 9 import java.util.Map; 10 import javax.annotation.CheckForNull; 11 import javax.annotation.Nullable; 12 import net.java.truecommons.cio.Entry; 13 import net.java.truecommons.cio.Entry.Access; 14 import net.java.truecommons.cio.Entry.Type; 15 import net.java.truecommons.cio.InputSocket; 16 import net.java.truecommons.cio.OutputSocket; 17 import net.java.truecommons.shed.BitField; 18 import net.java.truecommons.shed.ImplementationsShouldExtend; 19 import static net.java.truevfs.kernel.spec.FsAssertion.Level.*; 20 21 /** 22 * Provides read/write access to a file system. 23 * 24 * <h3>General Properties</h3> 25 * <p> 26 * The {@link FsModel#getMountPoint() mount point} of the 27 * {@linkplain #getModel() file system model} 28 * addresses the file system accessed by this controller. 29 * Where the methods of this abstract class accept a 30 * {@link FsNodeName file system node name} as a parameter, this MUST get 31 * resolved against the {@link FsModel#getMountPoint() mount point} URI of this 32 * controller's file system model. 33 * <p> 34 * As of TrueVFS 0.10, application level transactions are not supported, 35 * that is, multiple file system operations cannot get composed into a single 36 * application level transaction - support for this feature may be added in a 37 * future version. 38 * <p> 39 * However, individual file system operations do come with assertions about 40 * their atomicity, consistency, isolation and durability. 41 * Each method of this interface which is expected to access the file system 42 * (rather than just memory) is annotated with an {@link FsAssertion}. 43 * The annotation is {@link Inherited}, so the assertion forms part of the 44 * contract which any implementation of this interface should comply to. 45 * <p> 46 * Note that file system controllers are generally allowed to buffer any 47 * changes made to their file system. 48 * This is generally true for file system controllers which operate on archive 49 * files. 50 * This means that all changes made to the file system via this interface may 51 * not be entirely durable until they get committed by calling {@link #sync}. 52 * The annotations account for this stipulation by leaving the 53 * {@link FsAssertion#durable() durability} property undefined. 54 * <p> 55 * An implementation which wants to buffer its changes until {@code sync} gets 56 * called needs to notify the {@linkplain FsManager file system manager} by 57 * calling {@link FsModel#setMounted setMounted(true)} on the controller's 58 * file system model before the first change is commenced. 59 * Likewise, when {@code sync} gets called, the controller needs to notify the 60 * file system manager by calling {@code setMounted(false)} on the controller's 61 * file system model if and only if the {@code sync} has been successfully 62 * completed. 63 * This protocol enables proper management of the controller's life cycle. 64 * <p> 65 * Implementations should be safe for multi-threaded access. 66 * 67 * @see FsManager 68 * @see FsModel 69 * @see <a href="http://www.ietf.org/rfc/rfc2119.txt">RFC 2119: Key words for use in RFCs to Indicate Requirement Levels</a> 70 * @author Christian Schlichtherle 71 */ 72 @ImplementationsShouldExtend(FsAbstractController.class) 73 public interface FsController { 74 75 /** 76 * Returns the controller for the parent file system or {@code null} if 77 * and only if this file system is not federated, i.e. not a member of 78 * another file system. 79 * Multiple invocations must return the same object. 80 * 81 * @return The nullable controller for the parent file system. 82 */ 83 @Nullable FsController getParent(); 84 85 /** 86 * Returns the file system model. 87 * 88 * @return The file system model. 89 */ 90 FsModel getModel(); 91 92 /** 93 * Returns the file system node for the given {@code name} or {@code null} 94 * if it doesn't exist. 95 * Modifying the returned node does not show any effect on the file system 96 * and should result in an {@link UnsupportedOperationException}. 97 * 98 * @param options the options for accessing the file system node. 99 * @param name the name of the file system node. 100 * @return A file system node or {@code null} if no file system node 101 * exists for the given name. 102 * @throws IOException on any I/O error. 103 */ 104 @FsAssertion(atomic=YES, consistent=YES, isolated=YES, durable=NOT_APPLICABLE) 105 @CheckForNull FsNode node( 106 BitField<FsAccessOption> options, 107 FsNodeName name) 108 throws IOException; 109 110 /** 111 * Checks if the file system node for the given {@code name} exists when 112 * constrained by the given access {@code options} and permits the given 113 * access {@code types}. 114 * 115 * @param options the options for accessing the file system node. 116 * @param name the name of the file system node. 117 * @param types the types of the desired access. 118 * @throws IOException on any I/O error. 119 */ 120 @FsAssertion(atomic=YES, consistent=YES, isolated=YES, durable=NOT_APPLICABLE) 121 void checkAccess( 122 BitField<FsAccessOption> options, 123 FsNodeName name, 124 BitField<Access> types) 125 throws IOException; 126 127 /** 128 * Sets the named file system node as read-only. 129 * This method will fail for typical archive file system controller 130 * implementations because they do not support it. 131 * 132 * @param options the options for accessing the file system node. 133 * @param name the name of the file system node. 134 * @throws IOException on any I/O error or if this operation is not 135 * supported. 136 */ 137 @FsAssertion(atomic=YES, consistent=YES, isolated=YES) 138 void setReadOnly(BitField<FsAccessOption> options, FsNodeName name) 139 throws IOException; 140 141 /** 142 * Makes an attempt to set the last access time of all types in the given 143 * map for the file system node with the given name. 144 * If {@code false} is returned or an {@link IOException} is thrown, then 145 * still some of the last access times may have been set. 146 * Whether or not this is an atomic operation is specific to the 147 * implementation. 148 * 149 * @param options the options for accessing the file system node. 150 * @param name the name of the file system node. 151 * @param times the access times. 152 * @return {@code true} if and only if setting the access time for all 153 * types in {@code times} succeeded. 154 * @throws IOException on any I/O error. 155 * @throws NullPointerException if any key or value in the map is 156 * {@code null}. 157 */ 158 @FsAssertion(atomic=NO, consistent=YES, isolated=YES) 159 boolean setTime( 160 BitField<FsAccessOption> options, 161 FsNodeName name, 162 Map<Access, Long> times) 163 throws IOException; 164 165 /** 166 * Makes an attempt to set the last access time of all types in the given 167 * bit field for the file system node with the given name. 168 * If {@code false} is returned or an {@link IOException} is thrown, then 169 * still some of the last access times may have been set. 170 * 171 * @param options the options for accessing the file system node. 172 * @param name the name of the file system node. 173 * @param types the access types. 174 * @param value the last access time. 175 * @return {@code true} if and only if setting the access time for all 176 * types in {@code types} succeeded. 177 * @throws IOException on any I/O error. 178 */ 179 @FsAssertion(atomic=NO, consistent=YES, isolated=YES) 180 boolean setTime( 181 BitField<FsAccessOption> options, 182 FsNodeName name, 183 BitField<Access> types, 184 long value) 185 throws IOException; 186 187 /** 188 * Returns an input socket for reading the contents of the file system 189 * node addressed by the given name from the file system. 190 * Note that the assertions for this file system operation equally apply to 191 * any channel or stream created by the returned input socket! 192 * 193 * @param options the options for accessing the file system node. 194 * @param name the name of the file system node. 195 * @return An {@code InputSocket}. 196 */ 197 @FsAssertion(atomic=YES, consistent=YES, isolated=YES, durable=NOT_APPLICABLE) 198 InputSocket<? extends Entry> input( 199 BitField<FsAccessOption> options, 200 FsNodeName name); 201 202 /** 203 * Returns an output socket for writing the contents of the node addressed 204 * by the given name to the file system. 205 * Note that the assertions for this file system operation equally apply to 206 * any channel or stream created by the returned output socket! 207 * 208 * @param options the options for accessing the file system node. 209 * If {@link FsAccessOption#CREATE_PARENTS} is set, any missing 210 * parent directories shall get created with an undefined last 211 * modification time. 212 * @param name the name of the file system node. 213 * @param template if not {@code null}, then the file system node 214 * at the end of the chain shall inherit as much properties from 215 * this node as possible - with the exception of its name and type. 216 * @return An {@code OutputSocket}. 217 */ 218 @FsAssertion(atomic=YES, consistent=YES, isolated=YES) 219 OutputSocket<? extends Entry> output( 220 BitField<FsAccessOption> options, 221 FsNodeName name, 222 @CheckForNull Entry template); 223 224 /** 225 * Creates or replaces and finally links a chain of one or more entries 226 * for the given node {@code name} into the file system. 227 * 228 * @param options the options for accessing the file system node. 229 * If {@link FsAccessOption#CREATE_PARENTS} is set, any missing 230 * parent directories shall get created with an undefined last 231 * modification time. 232 * @param name the name of the file system node. 233 * @param type the file system node type. 234 * @param template if not {@code null}, then the file system node 235 * at the end of the chain shall inherit as much properties from 236 * this node as possible - with the exception of its name and type. 237 * @throws IOException on any I/O error, including but not limited to 238 * these reasons: 239 * <ul> 240 * <li>The file system is read only. 241 * <li>{@code name} contains characters which are not 242 * supported by the file system. 243 * <li>The node already exists and either the option 244 * {@link FsAccessOption#EXCLUSIVE} is set or the node is a 245 * directory. 246 * <li>The node exists as a different type. 247 * <li>A parent node exists but is not a directory. 248 * <li>A parent node is missing and {@code createParents} is 249 * {@code false}. 250 * </ul> 251 */ 252 @FsAssertion(atomic=YES, consistent=YES, isolated=YES) 253 void make( 254 BitField<FsAccessOption> options, 255 FsNodeName name, 256 Type type, 257 @CheckForNull Entry template) 258 throws IOException; 259 260 /** 261 * Removes the named file system node from the file system. 262 * If the named file system node is a directory, it must be empty. 263 * 264 * @param options the options for accessing the file system node. 265 * @param name the name of the file system node. 266 * @throws IOException on any I/O error. 267 */ 268 @FsAssertion(atomic=YES, consistent=YES, isolated=YES) 269 void unlink(BitField<FsAccessOption> options, FsNodeName name) 270 throws IOException; 271 272 /** 273 * Commits all unsynchronized changes to the contents of this file system 274 * to its parent file system, 275 * releases the associated resources (e.g. target archive files) for 276 * access by third parties (e.g. other processes), cleans up any temporary 277 * allocated resources (e.g. temporary files) and purges any cached data. 278 * Note that temporary resources may get allocated even if the federated 279 * file systems were accessed read-only. 280 * If this is not a federated file system, i.e. if its not a member of a 281 * parent file system, then nothing happens. 282 * Otherwise, the state of this file system controller is reset. 283 * <p> 284 * An implementation may ignore calls to this method if its stateless. 285 * 286 * @param options the options for synchronizing the file system. 287 * @throws FsSyncWarningException if <em>only</em> warning conditions 288 * apply. 289 * This implies that the respective parent file system has been 290 * synchronized with constraints, e.g. if an unclosed archive entry 291 * stream gets forcibly closed. 292 * @throws FsSyncException if any error conditions apply. 293 */ 294 @FsAssertion(atomic=NO, consistent=YES, isolated=YES) 295 void sync(BitField<FsSyncOption> options) throws FsSyncException; 296 297 /** 298 * A factory for {@linkplain FsController file system controllers}. 299 * <p> 300 * Implementations should be safe for multi-threaded access. 301 * 302 * @param <Context> The type of the calling context. 303 * @since TrueVFS 0.11 304 * @author Christian Schlichtherle 305 */ 306 interface Factory<Context> { 307 308 /** 309 * Returns a new file system controller for the mount point of the 310 * given file system model. 311 * This is a pure function without side effects. 312 * <p> 313 * When called, you may assert the following precondition: 314 * <pre>{@code 315 * assert null == parent 316 * ? null == model.getParent() 317 * : parent.getModel().equals(model.getParent()) 318 * }</pre> 319 * 320 * @param context the calling context. 321 * @param model the file system model. 322 * @param parent the nullable parent file system controller. 323 * @return A new file system controller for the mount point of the 324 * given file system model. 325 */ 326 FsController newController( 327 Context context, 328 FsModel model, 329 @CheckForNull FsController parent); 330 } 331 }