aboutsummaryrefslogtreecommitdiff
path: root/jimfs/src/main/java/com/google/common/jimfs/JimfsFileStore.java
blob: 910d231e5c33b43e75fd0a8c5a12344159a1cb2f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
/*
 * Copyright 2013 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.common.jimfs;

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import java.io.IOException;
import java.nio.file.FileStore;
import java.nio.file.LinkOption;
import java.nio.file.NoSuchFileException;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.FileAttributeView;
import java.nio.file.attribute.FileStoreAttributeView;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;

/**
 * {@link FileStore} implementation which provides methods for file creation, lookup and attribute
 * handling.
 *
 * <p>Most of these methods are actually implemented in another class: {@link FileTree} for lookup,
 * {@link FileFactory} for creating and copying files and {@link AttributeService} for attribute
 * handling. This class merely provides a single API through which to access the functionality of
 * those classes.
 *
 * @author Colin Decker
 */
final class JimfsFileStore extends FileStore {

  private final FileTree tree;
  private final HeapDisk disk;
  private final AttributeService attributes;
  private final FileFactory factory;
  private final ImmutableSet<Feature> supportedFeatures;
  private final FileSystemState state;

  private final Lock readLock;
  private final Lock writeLock;

  public JimfsFileStore(
      FileTree tree,
      FileFactory factory,
      HeapDisk disk,
      AttributeService attributes,
      ImmutableSet<Feature> supportedFeatures,
      FileSystemState state) {
    this.tree = checkNotNull(tree);
    this.factory = checkNotNull(factory);
    this.disk = checkNotNull(disk);
    this.attributes = checkNotNull(attributes);
    this.supportedFeatures = checkNotNull(supportedFeatures);
    this.state = checkNotNull(state);

    ReadWriteLock lock = new ReentrantReadWriteLock();
    this.readLock = lock.readLock();
    this.writeLock = lock.writeLock();
  }

  // internal use methods

  /** Returns the file system state object. */
  FileSystemState state() {
    return state;
  }

  /** Returns the read lock for this store. */
  Lock readLock() {
    return readLock;
  }

  /** Returns the write lock for this store. */
  Lock writeLock() {
    return writeLock;
  }

  /** Returns the names of the root directories in this store. */
  ImmutableSortedSet<Name> getRootDirectoryNames() {
    state.checkOpen();
    return tree.getRootDirectoryNames();
  }

  /** Returns the root directory with the given name or {@code null} if no such directory exists. */
  @NullableDecl
  Directory getRoot(Name name) {
    DirectoryEntry entry = tree.getRoot(name);
    return entry == null ? null : (Directory) entry.file();
  }

  /** Returns whether or not the given feature is supported by this file store. */
  boolean supportsFeature(Feature feature) {
    return supportedFeatures.contains(feature);
  }

  /**
   * Looks up the file at the given path using the given link options. If the path is relative, the
   * lookup is relative to the given working directory.
   *
   * @throws NoSuchFileException if an element of the path other than the final element does not
   *     resolve to a directory or symbolic link (e.g. it doesn't exist or is a regular file)
   * @throws IOException if a symbolic link cycle is detected or the depth of symbolic link
   *     recursion otherwise exceeds a threshold
   */
  DirectoryEntry lookUp(File workingDirectory, JimfsPath path, Set<? super LinkOption> options)
      throws IOException {
    state.checkOpen();
    return tree.lookUp(workingDirectory, path, options);
  }

  /** Returns a supplier that creates a new regular file. */
  Supplier<RegularFile> regularFileCreator() {
    state.checkOpen();
    return factory.regularFileCreator();
  }

  /** Returns a supplier that creates a new directory. */
  Supplier<Directory> directoryCreator() {
    state.checkOpen();
    return factory.directoryCreator();
  }

  /** Returns a supplier that creates a new symbolic link with the given target. */
  Supplier<SymbolicLink> symbolicLinkCreator(JimfsPath target) {
    state.checkOpen();
    return factory.symbolicLinkCreator(target);
  }

  /**
   * Creates a copy of the given file, copying its attributes as well according to the given {@code
   * attributeCopyOption}.
   */
  File copyWithoutContent(File file, AttributeCopyOption attributeCopyOption) throws IOException {
    File copy = factory.copyWithoutContent(file);
    setInitialAttributes(copy);
    attributes.copyAttributes(file, copy, attributeCopyOption);
    return copy;
  }

  /**
   * Sets initial attributes on the given file. Sets default attributes first, then attempts to set
   * the given user-provided attributes.
   */
  void setInitialAttributes(File file, FileAttribute<?>... attrs) {
    state.checkOpen();
    attributes.setInitialAttributes(file, attrs);
  }

  /**
   * Returns an attribute view of the given type for the given file lookup callback, or {@code null}
   * if the view type is not supported.
   */
  @NullableDecl
  <V extends FileAttributeView> V getFileAttributeView(FileLookup lookup, Class<V> type) {
    state.checkOpen();
    return attributes.getFileAttributeView(lookup, type);
  }

  /**
   * Returns a map containing the attributes described by the given string mapped to their values.
   */
  ImmutableMap<String, Object> readAttributes(File file, String attributes) {
    state.checkOpen();
    return this.attributes.readAttributes(file, attributes);
  }

  /**
   * Returns attributes of the given file as an object of the given type.
   *
   * @throws UnsupportedOperationException if the given attributes type is not supported
   */
  <A extends BasicFileAttributes> A readAttributes(File file, Class<A> type) {
    state.checkOpen();
    return attributes.readAttributes(file, type);
  }

  /** Sets the given attribute to the given value for the given file. */
  void setAttribute(File file, String attribute, Object value) {
    state.checkOpen();
    // TODO(cgdecker): Change attribute stuff to avoid the sad boolean parameter
    attributes.setAttribute(file, attribute, value, false);
  }

  /** Returns the file attribute views supported by this store. */
  ImmutableSet<String> supportedFileAttributeViews() {
    state.checkOpen();
    return attributes.supportedFileAttributeViews();
  }

  // methods implementing the FileStore API

  @Override
  public String name() {
    return "jimfs";
  }

  @Override
  public String type() {
    return "jimfs";
  }

  @Override
  public boolean isReadOnly() {
    return false;
  }

  @Override
  public long getTotalSpace() throws IOException {
    state.checkOpen();
    return disk.getTotalSpace();
  }

  @Override
  public long getUsableSpace() throws IOException {
    state.checkOpen();
    return getUnallocatedSpace();
  }

  @Override
  public long getUnallocatedSpace() throws IOException {
    state.checkOpen();
    return disk.getUnallocatedSpace();
  }

  @Override
  public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
    state.checkOpen();
    return attributes.supportsFileAttributeView(type);
  }

  @Override
  public boolean supportsFileAttributeView(String name) {
    state.checkOpen();
    return attributes.supportedFileAttributeViews().contains(name);
  }

  @Override
  public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> type) {
    state.checkOpen();
    return null; // no supported views
  }

  @Override
  public Object getAttribute(String attribute) throws IOException {
    throw new UnsupportedOperationException();
  }
}