• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.annotations.VisibleForTesting;
22 import com.google.common.base.MoreObjects;
23 import com.google.common.collect.HashBasedTable;
24 import com.google.common.collect.ImmutableSet;
25 import com.google.common.collect.Table;
26 import java.io.IOException;
27 import java.util.concurrent.locks.ReadWriteLock;
28 import org.checkerframework.checker.nullness.compatqual.NullableDecl;
29 
30 /**
31  * A file object, containing both the file's metadata and content.
32  *
33  * @author Colin Decker
34  */
35 public abstract class File {
36 
37   private final int id;
38 
39   private int links;
40 
41   private long creationTime;
42   private long lastAccessTime;
43   private long lastModifiedTime;
44 
45   @NullableDecl // null when only the basic view is used (default)
46   private Table<String, String, Object> attributes;
47 
File(int id)48   File(int id) {
49     this.id = id;
50 
51     long now = System.currentTimeMillis(); // TODO(cgdecker): Use a Clock
52     this.creationTime = now;
53     this.lastAccessTime = now;
54     this.lastModifiedTime = now;
55   }
56 
57   /** Returns the ID of this file. */
id()58   public int id() {
59     return id;
60   }
61 
62   /**
63    * Returns the size, in bytes, of this file's content. Directories and symbolic links have a size
64    * of 0.
65    */
size()66   public long size() {
67     return 0;
68   }
69 
70   /** Returns whether or not this file is a directory. */
isDirectory()71   public final boolean isDirectory() {
72     return this instanceof Directory;
73   }
74 
75   /** Returns whether or not this file is a regular file. */
isRegularFile()76   public final boolean isRegularFile() {
77     return this instanceof RegularFile;
78   }
79 
80   /** Returns whether or not this file is a symbolic link. */
isSymbolicLink()81   public final boolean isSymbolicLink() {
82     return this instanceof SymbolicLink;
83   }
84 
85   /**
86    * Creates a new file of the same type as this file with the given ID. Does not copy the content
87    * of this file unless the cost of copying the content is minimal. This is because this method is
88    * called with a hold on the file system's lock.
89    */
copyWithoutContent(int id)90   abstract File copyWithoutContent(int id);
91 
92   /**
93    * Copies the content of this file to the given file. The given file must be the same type of file
94    * as this file and should have no content.
95    *
96    * <p>This method is used for copying the content of a file after copying the file itself. Does
97    * nothing by default.
98    */
copyContentTo(File file)99   void copyContentTo(File file) throws IOException {}
100 
101   /**
102    * Returns the read-write lock for this file's content, or {@code null} if there is no content
103    * lock.
104    */
105   @NullableDecl
contentLock()106   ReadWriteLock contentLock() {
107     return null;
108   }
109 
110   /** Called when a stream or channel to this file is opened. */
opened()111   void opened() {}
112 
113   /**
114    * Called when a stream or channel to this file is closed. If there are no more streams or
115    * channels open to the file and it has been deleted, its contents may be deleted.
116    */
closed()117   void closed() {}
118 
119   /**
120    * Called when (a single link to) this file is deleted. There may be links remaining. Does nothing
121    * by default.
122    */
deleted()123   void deleted() {}
124 
125   /** Returns whether or not this file is a root directory of the file system. */
isRootDirectory()126   final boolean isRootDirectory() {
127     // only root directories have their parent link pointing to themselves
128     return isDirectory() && equals(((Directory) this).parent());
129   }
130 
131   /** Returns the current count of links to this file. */
links()132   public final synchronized int links() {
133     return links;
134   }
135 
136   /**
137    * Called when this file has been linked in a directory. The given entry is the new directory
138    * entry that links to this file.
139    */
linked(DirectoryEntry entry)140   void linked(DirectoryEntry entry) {
141     checkNotNull(entry);
142   }
143 
144   /** Called when this file has been unlinked from a directory, either for a move or delete. */
unlinked()145   void unlinked() {}
146 
147   /** Increments the link count for this file. */
incrementLinkCount()148   final synchronized void incrementLinkCount() {
149     links++;
150   }
151 
152   /** Decrements the link count for this file. */
decrementLinkCount()153   final synchronized void decrementLinkCount() {
154     links--;
155   }
156 
157   /** Gets the creation time of the file. */
158   @SuppressWarnings("GoodTime") // should return a java.time.Instant
getCreationTime()159   public final synchronized long getCreationTime() {
160     return creationTime;
161   }
162 
163   /** Gets the last access time of the file. */
164   @SuppressWarnings("GoodTime") // should return a java.time.Instant
getLastAccessTime()165   public final synchronized long getLastAccessTime() {
166     return lastAccessTime;
167   }
168 
169   /** Gets the last modified time of the file. */
170   @SuppressWarnings("GoodTime") // should return a java.time.Instant
getLastModifiedTime()171   public final synchronized long getLastModifiedTime() {
172     return lastModifiedTime;
173   }
174 
175   /** Sets the creation time of the file. */
setCreationTime(long creationTime)176   final synchronized void setCreationTime(long creationTime) {
177     this.creationTime = creationTime;
178   }
179 
180   /** Sets the last access time of the file. */
setLastAccessTime(long lastAccessTime)181   final synchronized void setLastAccessTime(long lastAccessTime) {
182     this.lastAccessTime = lastAccessTime;
183   }
184 
185   /** Sets the last modified time of the file. */
setLastModifiedTime(long lastModifiedTime)186   final synchronized void setLastModifiedTime(long lastModifiedTime) {
187     this.lastModifiedTime = lastModifiedTime;
188   }
189 
190   /** Sets the last access time of the file to the current time. */
updateAccessTime()191   final void updateAccessTime() {
192     setLastAccessTime(System.currentTimeMillis());
193   }
194 
195   /** Sets the last modified time of the file to the current time. */
updateModifiedTime()196   final void updateModifiedTime() {
197     setLastModifiedTime(System.currentTimeMillis());
198   }
199 
200   /**
201    * Returns the names of the attributes contained in the given attribute view in the file's
202    * attributes table.
203    */
getAttributeNames(String view)204   public final synchronized ImmutableSet<String> getAttributeNames(String view) {
205     if (attributes == null) {
206       return ImmutableSet.of();
207     }
208     return ImmutableSet.copyOf(attributes.row(view).keySet());
209   }
210 
211   /** Returns the attribute keys contained in the attributes map for the file. */
212   @VisibleForTesting
getAttributeKeys()213   final synchronized ImmutableSet<String> getAttributeKeys() {
214     if (attributes == null) {
215       return ImmutableSet.of();
216     }
217 
218     ImmutableSet.Builder<String> builder = ImmutableSet.builder();
219     for (Table.Cell<String, String, Object> cell : attributes.cellSet()) {
220       builder.add(cell.getRowKey() + ':' + cell.getColumnKey());
221     }
222     return builder.build();
223   }
224 
225   /** Gets the value of the given attribute in the given view. */
226   @NullableDecl
getAttribute(String view, String attribute)227   public final synchronized Object getAttribute(String view, String attribute) {
228     if (attributes == null) {
229       return null;
230     }
231     return attributes.get(view, attribute);
232   }
233 
234   /** Sets the given attribute in the given view to the given value. */
setAttribute(String view, String attribute, Object value)235   public final synchronized void setAttribute(String view, String attribute, Object value) {
236     if (attributes == null) {
237       attributes = HashBasedTable.create();
238     }
239     attributes.put(view, attribute, value);
240   }
241 
242   /** Deletes the given attribute from the given view. */
deleteAttribute(String view, String attribute)243   public final synchronized void deleteAttribute(String view, String attribute) {
244     if (attributes != null) {
245       attributes.remove(view, attribute);
246     }
247   }
248 
249   /** Copies basic attributes (file times) from this file to the given file. */
copyBasicAttributes(File target)250   final synchronized void copyBasicAttributes(File target) {
251     target.setFileTimes(creationTime, lastModifiedTime, lastAccessTime);
252   }
253 
setFileTimes( long creationTime, long lastModifiedTime, long lastAccessTime)254   private synchronized void setFileTimes(
255       long creationTime, long lastModifiedTime, long lastAccessTime) {
256     this.creationTime = creationTime;
257     this.lastModifiedTime = lastModifiedTime;
258     this.lastAccessTime = lastAccessTime;
259   }
260 
261   /** Copies the attributes from this file to the given file. */
copyAttributes(File target)262   final synchronized void copyAttributes(File target) {
263     copyBasicAttributes(target);
264     target.putAll(attributes);
265   }
266 
putAll(@ullableDecl Table<String, String, Object> attributes)267   private synchronized void putAll(@NullableDecl Table<String, String, Object> attributes) {
268     if (attributes != null && this.attributes != attributes) {
269       if (this.attributes == null) {
270         this.attributes = HashBasedTable.create();
271       }
272       this.attributes.putAll(attributes);
273     }
274   }
275 
276   @Override
toString()277   public final String toString() {
278     return MoreObjects.toStringHelper(this).add("id", id()).toString();
279   }
280 }
281