package com.github.marschall.memoryfilesystem; import static java.nio.file.attribute.PosixFilePermission.GROUP_EXECUTE; import static java.nio.file.attribute.PosixFilePermission.OTHERS_EXECUTE; import static java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE; import java.io.IOException; import java.nio.file.AccessDeniedException; import java.nio.file.AccessMode; import java.nio.file.DirectoryNotEmptyException; import java.nio.file.DirectoryStream; import java.nio.file.DirectoryStream.Filter; import java.nio.file.FileAlreadyExistsException; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributeView; import java.nio.file.attribute.PosixFilePermission; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; class MemoryDirectory extends MemoryEntry { private final Map<String, MemoryEntry> entries; private static final Set<PosixFilePermission> EXECUTE = EnumSet.of(OWNER_EXECUTE, GROUP_EXECUTE, OTHERS_EXECUTE); MemoryDirectory(String originalName) { this(originalName, EntryCreationContext.empty()); } MemoryDirectory(String originalName, EntryCreationContext context) { super(originalName, context); this.entries = new HashMap<>(); } @Override MemoryEntryAttributes newMemoryEntryAttributes(EntryCreationContext context) { return new MemoryDirectoryAttributes(context); } private static Set<PosixFilePermission> addExecute(Set<PosixFilePermission> perms) { Set<PosixFilePermission> copy = EnumSet.copyOf(perms); copy.addAll(EXECUTE); return copy; } DirectoryStream<Path> newDirectoryStream(Path basePath, Filter<? super Path> filter) throws AccessDeniedException { // REVIEW simply copying is not super scalable // REVIEW eager filtering might be nice this.checkAccess(AccessMode.EXECUTE); List<String> elements = new ArrayList<>(this.entries.size()); for (MemoryEntry entry : this.entries.values()) { elements.add(entry.getOriginalName()); } return new MemoryDirectoryStream(basePath, filter, elements); } MemoryEntry getEntry(String name) { // TODO atime? return this.entries.get(name); } MemoryEntry getEntryOrException(String name, Path path) throws IOException { MemoryEntry entry = this.getEntry(name); if (entry == null) { throw new NoSuchFileException(path.toString()); } return entry; } boolean isEmpty() { return this.entries.isEmpty(); } void checkEmpty(Path path) throws IOException { if (!this.isEmpty()) { throw new DirectoryNotEmptyException(path.toString()); } } // caller have to check for write permissions // we can't do it here because that may break operations that involve // two directories void addEntry(String name, MemoryEntry entry) throws IOException { MemoryEntry previous = this.entries.put(name, entry); if (previous != null) { // avoid double look up in common case // fix if we broke it this.entries.put(name, previous); // FIXME needs to be path throw new FileAlreadyExistsException("entry " + name + " already exists"); } this.modified(); } @Override public String toString() { return "directory(" + this.getOriginalName() + ')'; } //caller have to check for write permissions // we can't do it here because that may break operations that involve // two directories void removeEntry(String name) throws AccessDeniedException { // TODO check for result this.entries.remove(name); this.modified(); } static final class MemoryDirectoryAttributes extends MemoryEntryAttributes { MemoryDirectoryAttributes(EntryCreationContext context) { super(context); } @Override BasicFileAttributeView newBasicFileAttributeView() { return new MemoryDirectoryFileAttributesView(); } @Override long size() { return -1; } } }