1 /* 2 * Copyright 2013 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.jimfs; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 21 import com.google.common.base.Supplier; 22 import com.google.common.collect.ImmutableMap; 23 import com.google.common.collect.ImmutableSet; 24 import com.google.common.collect.ImmutableSortedSet; 25 import java.io.IOException; 26 import java.nio.file.FileStore; 27 import java.nio.file.LinkOption; 28 import java.nio.file.NoSuchFileException; 29 import java.nio.file.attribute.BasicFileAttributes; 30 import java.nio.file.attribute.FileAttribute; 31 import java.nio.file.attribute.FileAttributeView; 32 import java.nio.file.attribute.FileStoreAttributeView; 33 import java.util.Set; 34 import java.util.concurrent.locks.Lock; 35 import java.util.concurrent.locks.ReadWriteLock; 36 import java.util.concurrent.locks.ReentrantReadWriteLock; 37 import org.checkerframework.checker.nullness.compatqual.NullableDecl; 38 39 /** 40 * {@link FileStore} implementation which provides methods for file creation, lookup and attribute 41 * handling. 42 * 43 * <p>Most of these methods are actually implemented in another class: {@link FileTree} for lookup, 44 * {@link FileFactory} for creating and copying files and {@link AttributeService} for attribute 45 * handling. This class merely provides a single API through which to access the functionality of 46 * those classes. 47 * 48 * @author Colin Decker 49 */ 50 final class JimfsFileStore extends FileStore { 51 52 private final FileTree tree; 53 private final HeapDisk disk; 54 private final AttributeService attributes; 55 private final FileFactory factory; 56 private final ImmutableSet<Feature> supportedFeatures; 57 private final FileSystemState state; 58 59 private final Lock readLock; 60 private final Lock writeLock; 61 JimfsFileStore( FileTree tree, FileFactory factory, HeapDisk disk, AttributeService attributes, ImmutableSet<Feature> supportedFeatures, FileSystemState state)62 public JimfsFileStore( 63 FileTree tree, 64 FileFactory factory, 65 HeapDisk disk, 66 AttributeService attributes, 67 ImmutableSet<Feature> supportedFeatures, 68 FileSystemState state) { 69 this.tree = checkNotNull(tree); 70 this.factory = checkNotNull(factory); 71 this.disk = checkNotNull(disk); 72 this.attributes = checkNotNull(attributes); 73 this.supportedFeatures = checkNotNull(supportedFeatures); 74 this.state = checkNotNull(state); 75 76 ReadWriteLock lock = new ReentrantReadWriteLock(); 77 this.readLock = lock.readLock(); 78 this.writeLock = lock.writeLock(); 79 } 80 81 // internal use methods 82 83 /** Returns the file system state object. */ state()84 FileSystemState state() { 85 return state; 86 } 87 88 /** Returns the read lock for this store. */ readLock()89 Lock readLock() { 90 return readLock; 91 } 92 93 /** Returns the write lock for this store. */ writeLock()94 Lock writeLock() { 95 return writeLock; 96 } 97 98 /** Returns the names of the root directories in this store. */ getRootDirectoryNames()99 ImmutableSortedSet<Name> getRootDirectoryNames() { 100 state.checkOpen(); 101 return tree.getRootDirectoryNames(); 102 } 103 104 /** Returns the root directory with the given name or {@code null} if no such directory exists. */ 105 @NullableDecl getRoot(Name name)106 Directory getRoot(Name name) { 107 DirectoryEntry entry = tree.getRoot(name); 108 return entry == null ? null : (Directory) entry.file(); 109 } 110 111 /** Returns whether or not the given feature is supported by this file store. */ supportsFeature(Feature feature)112 boolean supportsFeature(Feature feature) { 113 return supportedFeatures.contains(feature); 114 } 115 116 /** 117 * Looks up the file at the given path using the given link options. If the path is relative, the 118 * lookup is relative to the given working directory. 119 * 120 * @throws NoSuchFileException if an element of the path other than the final element does not 121 * resolve to a directory or symbolic link (e.g. it doesn't exist or is a regular file) 122 * @throws IOException if a symbolic link cycle is detected or the depth of symbolic link 123 * recursion otherwise exceeds a threshold 124 */ lookUp(File workingDirectory, JimfsPath path, Set<? super LinkOption> options)125 DirectoryEntry lookUp(File workingDirectory, JimfsPath path, Set<? super LinkOption> options) 126 throws IOException { 127 state.checkOpen(); 128 return tree.lookUp(workingDirectory, path, options); 129 } 130 131 /** Returns a supplier that creates a new regular file. */ regularFileCreator()132 Supplier<RegularFile> regularFileCreator() { 133 state.checkOpen(); 134 return factory.regularFileCreator(); 135 } 136 137 /** Returns a supplier that creates a new directory. */ directoryCreator()138 Supplier<Directory> directoryCreator() { 139 state.checkOpen(); 140 return factory.directoryCreator(); 141 } 142 143 /** Returns a supplier that creates a new symbolic link with the given target. */ symbolicLinkCreator(JimfsPath target)144 Supplier<SymbolicLink> symbolicLinkCreator(JimfsPath target) { 145 state.checkOpen(); 146 return factory.symbolicLinkCreator(target); 147 } 148 149 /** 150 * Creates a copy of the given file, copying its attributes as well according to the given {@code 151 * attributeCopyOption}. 152 */ copyWithoutContent(File file, AttributeCopyOption attributeCopyOption)153 File copyWithoutContent(File file, AttributeCopyOption attributeCopyOption) throws IOException { 154 File copy = factory.copyWithoutContent(file); 155 setInitialAttributes(copy); 156 attributes.copyAttributes(file, copy, attributeCopyOption); 157 return copy; 158 } 159 160 /** 161 * Sets initial attributes on the given file. Sets default attributes first, then attempts to set 162 * the given user-provided attributes. 163 */ setInitialAttributes(File file, FileAttribute<?>... attrs)164 void setInitialAttributes(File file, FileAttribute<?>... attrs) { 165 state.checkOpen(); 166 attributes.setInitialAttributes(file, attrs); 167 } 168 169 /** 170 * Returns an attribute view of the given type for the given file lookup callback, or {@code null} 171 * if the view type is not supported. 172 */ 173 @NullableDecl getFileAttributeView(FileLookup lookup, Class<V> type)174 <V extends FileAttributeView> V getFileAttributeView(FileLookup lookup, Class<V> type) { 175 state.checkOpen(); 176 return attributes.getFileAttributeView(lookup, type); 177 } 178 179 /** 180 * Returns a map containing the attributes described by the given string mapped to their values. 181 */ readAttributes(File file, String attributes)182 ImmutableMap<String, Object> readAttributes(File file, String attributes) { 183 state.checkOpen(); 184 return this.attributes.readAttributes(file, attributes); 185 } 186 187 /** 188 * Returns attributes of the given file as an object of the given type. 189 * 190 * @throws UnsupportedOperationException if the given attributes type is not supported 191 */ readAttributes(File file, Class<A> type)192 <A extends BasicFileAttributes> A readAttributes(File file, Class<A> type) { 193 state.checkOpen(); 194 return attributes.readAttributes(file, type); 195 } 196 197 /** Sets the given attribute to the given value for the given file. */ setAttribute(File file, String attribute, Object value)198 void setAttribute(File file, String attribute, Object value) { 199 state.checkOpen(); 200 // TODO(cgdecker): Change attribute stuff to avoid the sad boolean parameter 201 attributes.setAttribute(file, attribute, value, false); 202 } 203 204 /** Returns the file attribute views supported by this store. */ supportedFileAttributeViews()205 ImmutableSet<String> supportedFileAttributeViews() { 206 state.checkOpen(); 207 return attributes.supportedFileAttributeViews(); 208 } 209 210 // methods implementing the FileStore API 211 212 @Override name()213 public String name() { 214 return "jimfs"; 215 } 216 217 @Override type()218 public String type() { 219 return "jimfs"; 220 } 221 222 @Override isReadOnly()223 public boolean isReadOnly() { 224 return false; 225 } 226 227 @Override getTotalSpace()228 public long getTotalSpace() throws IOException { 229 state.checkOpen(); 230 return disk.getTotalSpace(); 231 } 232 233 @Override getUsableSpace()234 public long getUsableSpace() throws IOException { 235 state.checkOpen(); 236 return getUnallocatedSpace(); 237 } 238 239 @Override getUnallocatedSpace()240 public long getUnallocatedSpace() throws IOException { 241 state.checkOpen(); 242 return disk.getUnallocatedSpace(); 243 } 244 245 @Override supportsFileAttributeView(Class<? extends FileAttributeView> type)246 public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) { 247 state.checkOpen(); 248 return attributes.supportsFileAttributeView(type); 249 } 250 251 @Override supportsFileAttributeView(String name)252 public boolean supportsFileAttributeView(String name) { 253 state.checkOpen(); 254 return attributes.supportedFileAttributeViews().contains(name); 255 } 256 257 @Override getFileStoreAttributeView(Class<V> type)258 public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> type) { 259 state.checkOpen(); 260 return null; // no supported views 261 } 262 263 @Override getAttribute(String attribute)264 public Object getAttribute(String attribute) throws IOException { 265 throw new UnsupportedOperationException(); 266 } 267 } 268