/** * Returns the entry for the given name in this table or null if no such entry exists. */ @Nullable public DirectoryEntry get(Name name) { int index = bucketIndex(name, table.length); DirectoryEntry entry = table[index]; while (entry != null) { if (name.equals(entry.name())) { return entry; } entry = entry.next; } return null; }
private boolean expandIfNeeded() { if (entryCount <= resizeThreshold) { return false; } DirectoryEntry[] newTable = new DirectoryEntry[table.length << 1]; // redistribute all current entries in the new table for (DirectoryEntry entry : table) { while (entry != null) { int index = bucketIndex(entry.name(), newTable.length); addToBucket(index, newTable, entry); DirectoryEntry next = entry.next; // set entry.next to null; it's always the last entry in its bucket after being added entry.next = null; entry = next; } } this.table = newTable; resizeThreshold <<= 1; return true; }
/** * Creates an immutable sorted snapshot of the names this directory contains, excluding "." and * "..". */ public ImmutableSortedSet<Name> snapshot() { ImmutableSortedSet.Builder<Name> builder = new ImmutableSortedSet.Builder<>(Name.displayOrdering()); for (DirectoryEntry entry : this) { if (!isReserved(entry.name())) { builder.add(entry.name()); } } return builder.build(); }
/** * Returns a snapshot mapping the names of each file in the directory at the given path to the * last modified time of that file. */ public ImmutableMap<Name, Long> snapshotModifiedTimes(JimfsPath path) throws IOException { ImmutableMap.Builder<Name, Long> modifiedTimes = ImmutableMap.builder(); store.readLock().lock(); try { Directory dir = (Directory) lookUp(path, Options.FOLLOW_LINKS) .requireDirectory(path) .file(); // TODO(cgdecker): Investigate whether WatchServices should keep a reference to the actual // directory when SecureDirectoryStream is supported rather than looking up the directory // each time the WatchService polls for (DirectoryEntry entry : dir) { if (!entry.name().equals(Name.SELF) && !entry.name().equals(Name.PARENT)) { modifiedTimes.put(entry.name(), entry.file().getLastModifiedTime()); } } return modifiedTimes.build(); } finally { store.readLock().unlock(); } }
/** * Gets the {@linkplain Path#toRealPath(LinkOption...) real path} to the file located by the * given path. */ public JimfsPath toRealPath( JimfsPath path, PathService pathService, Set<? super LinkOption> options) throws IOException { checkNotNull(path); checkNotNull(options); store.readLock().lock(); try { DirectoryEntry entry = lookUp(path, options).requireExists(path); List<Name> names = new ArrayList<>(); names.add(entry.name()); while (!entry.file().isRootDirectory()) { entry = entry.directory().entryInParent(); names.add(entry.name()); } // names are ordered last to first in the list, so get the reverse view List<Name> reversed = Lists.reverse(names); Name root = reversed.remove(0); return pathService.createPath(root, reversed); } finally { store.readLock().unlock(); } }
int index = bucketIndex(entry.name(), table.length); DirectoryEntry curr = table[index]; while (curr != null) { if (curr.name().equals(entry.name())) { if (overwriteExisting) { return; } else { throw new IllegalArgumentException("entry '" + entry.name() + "' already exists"); index = bucketIndex(entry.name(), table.length); addToBucket(index, table, entry); } else {
/** * Removes and returns the entry for the given name from the directory. * * @throws IllegalArgumentException if there is no entry with the given name in the directory */ @VisibleForTesting DirectoryEntry remove(Name name) { int index = bucketIndex(name, table.length); DirectoryEntry prev = null; DirectoryEntry entry = table[index]; while (entry != null) { if (name.equals(entry.name())) { if (prev != null) { prev.next = entry.next; } else { table[index] = entry.next; } entry.next = null; entryCount--; entry.file().decrementLinkCount(); return entry; } prev = entry; entry = entry.next; } throw new IllegalArgumentException("no entry matching '" + name + "' in this directory"); }
/** * Returns the entry for the file in its parent directory. This will be the given entry unless the * name for the entry is "." or "..", in which the directory linking to the file is not the file's * parent directory. In that case, we know the file must be a directory ("." and ".." can only * link to directories), so we can just get the entry in the directory's parent directory that * links to it. So, for example, if we have a directory "foo" that contains a directory "bar" and * we find an entry [bar -> "." -> bar], we instead return the entry for bar in its parent, * [foo -> "bar" -> bar]. */ @Nullable private DirectoryEntry getRealEntry(DirectoryEntry entry) { Name name = entry.name(); if (name.equals(Name.SELF) || name.equals(Name.PARENT)) { Directory dir = toDirectory(entry.file()); assert dir != null; return dir.entryInParent(); } else { return entry; } }
/** * Deletes the given directory entry from its parent directory. */ private void delete(DirectoryEntry entry, DeleteMode deleteMode, JimfsPath pathForException) throws IOException { Directory parent = entry.directory(); File file = entry.file(); checkDeletable(file, deleteMode, pathForException); parent.unlink(entry.name()); parent.updateModifiedTime(); file.deleted(); }
/** * Returns the entry for the given name in this table or null if no such entry exists. */ @Nullable public DirectoryEntry get(Name name) { int index = bucketIndex(name, table.length); DirectoryEntry entry = table[index]; while (entry != null) { if (name.equals(entry.name())) { return entry; } entry = entry.next; } return null; }
private boolean expandIfNeeded() { if (entryCount <= resizeThreshold) { return false; } DirectoryEntry[] newTable = new DirectoryEntry[table.length << 1]; // redistribute all current entries in the new table for (DirectoryEntry entry : table) { while (entry != null) { int index = bucketIndex(entry.name(), newTable.length); addToBucket(index, newTable, entry); DirectoryEntry next = entry.next; // set entry.next to null; it's always the last entry in its bucket after being added entry.next = null; entry = next; } } this.table = newTable; resizeThreshold <<= 1; return true; }
/** * Creates an immutable sorted snapshot of the names this directory contains, excluding "." and * "..". */ public ImmutableSortedSet<Name> snapshot() { ImmutableSortedSet.Builder<Name> builder = new ImmutableSortedSet.Builder<>(Name.displayOrdering()); for (DirectoryEntry entry : this) { if (!isReserved(entry.name())) { builder.add(entry.name()); } } return builder.build(); }
/** * Gets the {@linkplain Path#toRealPath(LinkOption...) real path} to the file located by the * given path. */ public JimfsPath toRealPath( JimfsPath path, PathService pathService, Set<? super LinkOption> options) throws IOException { checkNotNull(path); checkNotNull(options); store.readLock().lock(); try { DirectoryEntry entry = lookUp(path, options).requireExists(path); List<Name> names = new ArrayList<>(); names.add(entry.name()); while (!entry.file().isRootDirectory()) { entry = entry.directory().entryInParent(); names.add(entry.name()); } // names are ordered last to first in the list, so get the reverse view List<Name> reversed = Lists.reverse(names); Name root = reversed.remove(0); return pathService.createPath(root, reversed); } finally { store.readLock().unlock(); } }
/** * Returns a snapshot mapping the names of each file in the directory at the given path to the * last modified time of that file. */ public ImmutableMap<Name, Long> snapshotModifiedTimes(JimfsPath path) throws IOException { ImmutableMap.Builder<Name, Long> modifiedTimes = ImmutableMap.builder(); store.readLock().lock(); try { Directory dir = (Directory) lookUp(path, Options.FOLLOW_LINKS) .requireDirectory(path) .file(); // TODO(cgdecker): Investigate whether WatchServices should keep a reference to the actual // directory when SecureDirectoryStream is supported rather than looking up the directory // each time the WatchService polls for (DirectoryEntry entry : dir) { if (!entry.name().equals(Name.SELF) && !entry.name().equals(Name.PARENT)) { modifiedTimes.put(entry.name(), entry.file().getLastModifiedTime()); } } return modifiedTimes.build(); } finally { store.readLock().unlock(); } }
int index = bucketIndex(entry.name(), table.length); DirectoryEntry curr = table[index]; while (curr != null) { if (curr.name().equals(entry.name())) { if (overwriteExisting) { return; } else { throw new IllegalArgumentException("entry '" + entry.name() + "' already exists"); index = bucketIndex(entry.name(), table.length); addToBucket(index, table, entry); } else {
/** * Removes and returns the entry for the given name from the directory. * * @throws IllegalArgumentException if there is no entry with the given name in the directory */ @VisibleForTesting DirectoryEntry remove(Name name) { int index = bucketIndex(name, table.length); DirectoryEntry prev = null; DirectoryEntry entry = table[index]; while (entry != null) { if (name.equals(entry.name())) { if (prev != null) { prev.next = entry.next; } else { table[index] = entry.next; } entry.next = null; entryCount--; entry.file().decrementLinkCount(); return entry; } prev = entry; entry = entry.next; } throw new IllegalArgumentException("no entry matching '" + name + "' in this directory"); }
/** * Returns the entry for the file in its parent directory. This will be the given entry unless the * name for the entry is "." or "..", in which the directory linking to the file is not the file's * parent directory. In that case, we know the file must be a directory ("." and ".." can only * link to directories), so we can just get the entry in the directory's parent directory that * links to it. So, for example, if we have a directory "foo" that contains a directory "bar" and * we find an entry [bar -> "." -> bar], we instead return the entry for bar in its parent, * [foo -> "bar" -> bar]. */ @Nullable private DirectoryEntry getRealEntry(DirectoryEntry entry) { Name name = entry.name(); if (name.equals(Name.SELF) || name.equals(Name.PARENT)) { Directory dir = toDirectory(entry.file()); assert dir != null; return dir.entryInParent(); } else { return entry; } }
/** * Deletes the given directory entry from its parent directory. */ private void delete(DirectoryEntry entry, DeleteMode deleteMode, JimfsPath pathForException) throws IOException { Directory parent = entry.directory(); File file = entry.file(); checkDeletable(file, deleteMode, pathForException); parent.unlink(entry.name()); parent.updateModifiedTime(); file.deleted(); }