@Override void linked(DirectoryEntry entry) { File parent = entry.directory(); // handles null check this.entryInParent = entry; forcePut(new DirectoryEntry(this, Name.PARENT, parent)); }
File file = entry.file(); if (file.isSymbolicLink()) { DirectoryEntry linkResult = followSymbolicLink(dir, (SymbolicLink) file, linkDepth); dir = linkResult.fileOrNull(); } else { dir = file;
@Override public File lookup() throws IOException { return lookUpWithLock(path, options) .requireExists(path) .file(); } },
/** * 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(); }
/** * 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(); } }
existingView .lookUp(existing, Options.FOLLOW_LINKS) .requireExists(existing) .file(); if (!existingFile.isRegularFile()) { throw new FileSystemException( lookUp(link, Options.NOFOLLOW_LINKS).requireDoesNotExist(link).directory();
DirectoryEntry sourceEntry = lookUp(source, options).requireExists(source); DirectoryEntry destEntry = destView.lookUp(dest, Options.NOFOLLOW_LINKS); Directory sourceParent = sourceEntry.directory(); sourceFile = sourceEntry.file(); Directory destParent = destEntry.directory(); if (destEntry.exists()) { if (destEntry.file().equals(sourceFile)) { return; } else if (options.contains(REPLACE_EXISTING)) {
/** * 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 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(); } }
/** * Returns the target of the symbolic link at the given path. */ public JimfsPath readSymbolicLink(JimfsPath path) throws IOException { if (!store.supportsFeature(Feature.SYMBOLIC_LINKS)) { throw new UnsupportedOperationException(); } SymbolicLink symbolicLink = (SymbolicLink) lookUpWithLock(path, Options.NOFOLLOW_LINKS) .requireSymbolicLink(path) .file(); return symbolicLink.target(); }
/** * Creates a new directory stream for the directory located by the given path. The given * {@code basePathForStream} is that base path that the returned stream will use. This will be * the same as {@code dir} except for streams created relative to another secure stream. */ public DirectoryStream<Path> newDirectoryStream( JimfsPath dir, DirectoryStream.Filter<? super Path> filter, Set<? super LinkOption> options, JimfsPath basePathForStream) throws IOException { Directory file = (Directory) lookUpWithLock(dir, options) .requireDirectory(dir) .file(); FileSystemView view = new FileSystemView(store, file, basePathForStream); JimfsSecureDirectoryStream stream = new JimfsSecureDirectoryStream(view, filter, state()); return store.supportsFeature(Feature.SECURE_DIRECTORY_STREAM) ? stream : new DowngradedDirectoryStream(stream); }
/** * Looks up the last element of a path. */ @Nullable private DirectoryEntry lookUpLast( @Nullable File dir, Name name, Set<? super LinkOption> options, int linkDepth) throws IOException { Directory directory = toDirectory(dir); if (directory == null) { return null; } DirectoryEntry entry = directory.get(name); if (entry == null) { return new DirectoryEntry(directory, name, null); } File file = entry.file(); if (!options.contains(LinkOption.NOFOLLOW_LINKS) && file.isSymbolicLink()) { return followSymbolicLink(dir, (SymbolicLink) file, linkDepth); } return getRealEntry(entry); }
/** * Looks up the regular file at the given path, throwing an exception if the file isn't a regular * file. Returns null if the file did not exist. */ @Nullable private RegularFile lookUpRegularFile(JimfsPath path, Set<OpenOption> options) throws IOException { store.readLock().lock(); try { DirectoryEntry entry = lookUp(path, options); if (entry.exists()) { File file = entry.file(); if (!file.isRegularFile()) { throw new FileSystemException(path.toString(), null, "not a regular file"); } return open((RegularFile) file, options); } else { return null; } } finally { store.readLock().unlock(); } }
private Directory(int id, Name rootName) { this(id); linked(new DirectoryEntry(this, rootName, this)); }
/** * Returns the root directory with the given name or {@code null} if no such directory exists. */ @Nullable Directory getRoot(Name name) { DirectoryEntry entry = tree.getRoot(name); return entry == null ? null : (Directory) entry.file(); }
/** * Returns the file this entry links to. * * @throws IllegalStateException if the file does not exist */ public File file() { checkState(exists()); return file; }
/** * 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; }
/** * Checks access to the file at the given path for the given modes. Since access controls are not * implemented for this file system, this just checks that the file exists. */ public void checkAccess(JimfsPath path) throws IOException { // just check that the file exists lookUpWithLock(path, Options.FOLLOW_LINKS).requireExists(path); }
/** * Returns the parent of this directory. If this directory has been deleted, this returns the * directory it was in when it was deleted. */ public Directory parent() { return entryInParent.directory(); }