Skip to content

Commit

Permalink
Implement ifExists
Browse files Browse the repository at this point in the history
Fixes #133
Fixes #134
  • Loading branch information
marschall committed Dec 29, 2023
1 parent 2ee814f commit 71d44b7
Showing 1 changed file with 151 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
Expand Down Expand Up @@ -402,7 +403,6 @@ static final class GetEntryResult {
this.linkTarget = linkTarget;
}


}

private MemoryFile getFile(AbstractPath path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {
Expand Down Expand Up @@ -644,11 +644,29 @@ boolean isDirectory(AbstractPath path) {
}
}

boolean exists(AbstractPath path, LinkOption... options) {
try {
return this.accessFileReadingIfExists(path, Options.isFollowSymLinks(options), entry -> true).orElse(Boolean.FALSE);
} catch (IOException e) {
return false;
}
}

<A extends BasicFileAttributes> A readAttributes(AbstractPath path, Class<A> type, LinkOption... options) throws IOException {
this.checker.check();
return this.accessFileReading(path, Options.isFollowSymLinks(options), entry -> entry.readAttributes(type));
}

<A extends BasicFileAttributes> A readAttributesIfExists(AbstractPath path, Class<A> type, LinkOption... options) throws IOException {
this.checker.check();
Optional<A> result = this.accessFileReadingIfExists(path, Options.isFollowSymLinks(options), entry -> entry.readAttributes(type));
if (result.isPresent()) {
return result.get();
} else {
return null;
}
}

<V extends FileAttributeView> V getLazyFileAttributeView(AbstractPath path, Class<V> type, LinkOption... options) {
if (type != BasicFileAttributeView.class && !this.additionalViews.contains(type)) {
// unsupported view, specification requires null
Expand Down Expand Up @@ -685,6 +703,14 @@ private <R> R accessFileWriting(AbstractPath path, boolean followSymLinks, Memor
return this.accessFile(path, followSymLinks, LockType.WRITE, callback);
}

private <R> Optional<R> accessFileReadingIfExists(AbstractPath path, boolean followSymLinks, MemoryEntryBlock<? extends R> callback) throws IOException {
return this.accessFileIfExists(path, followSymLinks, LockType.READ, callback);
}

private <R> Optional<R> accessFileWritingIfExists(AbstractPath path, boolean followSymLinks, MemoryEntryBlock<? extends R> callback) throws IOException {
return this.accessFileIfExists(path, followSymLinks, LockType.WRITE, callback);
}

private <R> R accessFile(AbstractPath path, boolean followSymLinks, LockType lockType, MemoryEntryBlock<? extends R> callback) throws IOException {
this.checker.check();
AbstractPath absolutePath = (AbstractPath) path.toAbsolutePath().normalize();
Expand All @@ -698,6 +724,19 @@ private <R> R accessFile(AbstractPath path, boolean followSymLinks, LockType loc
return this.withLockDo(root, absolutePath, encounteredSymlinks, followSymLinks, lockType, callback);
}

private <R> Optional<R> accessFileIfExists(AbstractPath path, boolean followSymLinks, LockType lockType, MemoryEntryBlock<? extends R> callback) throws IOException {
this.checker.check();
AbstractPath absolutePath = (AbstractPath) path.toAbsolutePath().normalize();
MemoryDirectory root = this.getRootDirectory(absolutePath);
Set<MemorySymbolicLink> encounteredSymlinks;
if (followSymLinks) {
encounteredSymlinks = new HashSet<>(4);
} else {
encounteredSymlinks = Collections.emptySet();
}
return this.withLockDoIfExists(root, absolutePath, encounteredSymlinks, followSymLinks, lockType, callback);
}


private <R> R withWriteLockOnLastDo(MemoryDirectory root, AbstractPath path, boolean followSymLinks, MemoryDirectoryBlock<R> callback) throws IOException {
Set<MemorySymbolicLink> encounteredSymlinks;
Expand Down Expand Up @@ -727,6 +766,15 @@ private <R> R accessDirectoryWriting(AbstractPath path, boolean followSymLinks,
});
}

private <R> Optional<R> accessDirectoryWritingIfExists(AbstractPath path, boolean followSymLinks, MemoryDirectoryBlock<R> callback) throws IOException {
return this.accessFileWritingIfExists(path, followSymLinks, entry -> {
if (!(entry instanceof MemoryDirectory)) {
throw new NotDirectoryException(path.toString());
}
return callback.value((MemoryDirectory) entry);
});
}

private <R> R withReadLockDo(MemoryDirectory root, AbstractPath path, boolean followSymLinks, MemoryEntryBlock<? extends R> callback) throws IOException {
Set<MemorySymbolicLink> encounteredSymlinks;
if (followSymLinks) {
Expand Down Expand Up @@ -800,6 +848,72 @@ private <R> R withLockDo(MemoryDirectory root, AbstractPath path, Set<MemorySymb
}
}

private <R> Optional<R> withLockDoIfExists(MemoryDirectory root, AbstractPath path, Set<MemorySymbolicLink> encounteredLinks, boolean followSymLinks, LockType lockType, MemoryEntryBlock<? extends R> callback) throws IOException {
if (path.isRoot()) {
try (AutoRelease lock = root.lock(lockType)) {
return Optional.of(callback.value(root));
}
} else if (path instanceof ElementPath) {
Optional<R> result = null;
Path newLookUpPath = null;

ElementPath elementPath = (ElementPath) path;
List<String> nameElements = elementPath.getNameElements();
int pathElementCount = nameElements.size();
List<AutoRelease> locks = new ArrayList<>(pathElementCount + 1);
try {
locks.add(root.readLock());
MemoryDirectory parent = root;
for (int i = 0; i < pathElementCount; ++i) {
String fileName = nameElements.get(i);
String key = this.lookUpTransformer.transform(fileName);
MemoryEntry current = parent.getEntry(key);
if (current == null) {
result = Optional.empty();
break;
}
boolean isLast = i == pathElementCount - 1;
if (isLast) {
locks.add(current.lock(lockType));
} else {
locks.add(current.readLock());
}

if (followSymLinks && current instanceof MemorySymbolicLink) {
MemorySymbolicLink link = (MemorySymbolicLink) current;
if (!encounteredLinks.add(link)) {
throw new FileSystemLoopException(path.toString());
}
newLookUpPath = this.resolveSymlink(path, link, nameElements, pathElementCount, i);
break;
}

if (isLast) {
result = Optional.of(callback.value(current));
} else if (current instanceof MemoryDirectory) {
parent = (MemoryDirectory) current;
} else {
throw new NotDirectoryException(path.toString());
}

}
} finally {
for (int i = locks.size() - 1; i >= 0; --i) {
AutoRelease lock = locks.get(i);
lock.close();
}
}
if (newLookUpPath == null) {
return result;
} else {
return this.withLockDoIfExists(root, (AbstractPath) newLookUpPath.normalize(), encounteredLinks, followSymLinks, lockType, callback);
}

} else {
throw new IllegalArgumentException("unknown path type" + path);
}
}

private Path resolveSymlink(AbstractPath path, MemorySymbolicLink link, List<String> nameElements, int pathElementCount, int currentNameElementIndex) {
Path newLookUpPath;
Path symLinkTarget = link.getTarget();
Expand Down Expand Up @@ -1038,7 +1152,6 @@ MemoryDirectory getTargetParent(MemoryDirectory firstDirectory, MemoryDirectory

}


void delete(AbstractPath abstractPath) throws IOException {
try (AutoRelease autoRelease = autoRelease(this.pathOrderingLock.readLock())) {
AbstractPath absolutePath = (AbstractPath) abstractPath.toAbsolutePath().normalize();
Expand Down Expand Up @@ -1072,14 +1185,49 @@ void delete(AbstractPath abstractPath) throws IOException {
}
}

boolean deleteIfExists(AbstractPath abstractPath) throws IOException {
try (AutoRelease autoRelease = autoRelease(this.pathOrderingLock.readLock())) {
AbstractPath absolutePath = (AbstractPath) abstractPath.toAbsolutePath().normalize();
if (absolutePath.isRoot()) {
throw new FileSystemException(abstractPath.toString(), null, "can not delete root");
}
ElementPath elementPath = (ElementPath) absolutePath;

AbstractPath parent = (AbstractPath) elementPath.getParent();
return this.accessDirectoryWritingIfExists(parent, true, directory -> {
String fileName = elementPath.getLastNameElement();
String key = MemoryFileSystem.this.lookUpTransformer.transform(fileName);
MemoryEntry child = directory.getEntry(key);
if (child != null) {
try (AutoRelease lock = child.writeLock()) {
if (child instanceof MemoryDirectory) {
MemoryDirectory childDirectory = (MemoryDirectory) child;
childDirectory.checkEmpty(abstractPath);
}
if (child instanceof MemoryFile) {
MemoryFile file = (MemoryFile) child;
if (file.openCount() > 0) {
throw new FileSystemException(abstractPath.toString(), null, "file still open");
}
file.markForDeletion();
}
directory.checkAccess(WRITE);
directory.removeEntry(key);
}
return true;
} else {
return false;
}
}).orElse(Boolean.FALSE);
}
}

@Override
public FileSystemProvider provider() {
this.checker.check();
return this.provider;
}


@Override
@javax.annotation.PreDestroy
@jakarta.annotation.PreDestroy
Expand All @@ -1093,20 +1241,17 @@ public void close() {
}
}


@Override
public boolean isOpen() {
return this.checker.isOpen();
}


@Override
public boolean isReadOnly() {
this.checker.check();
return this.store.isReadOnly();
}


@Override
public String getSeparator() {
this.checker.check();
Expand All @@ -1121,14 +1266,12 @@ public Iterable<Path> getRootDirectories() {
return (Iterable<Path>) ((Object) this.roots.keySet());
}


@Override
public Iterable<FileStore> getFileStores() {
this.checker.check();
return this.stores;
}


@Override
public Set<String> supportedFileAttributeViews() {
this.checker.check();
Expand Down Expand Up @@ -1168,14 +1311,12 @@ public PathMatcher getPathMatcher(String syntaxAndPattern) {
throw new UnsupportedOperationException("unsupported syntax \"" + syntax + "\"");
}


@Override
public MemoryUserPrincipalLookupService getUserPrincipalLookupService() {
this.checker.check();
return this.userPrincipalLookupService;
}


@Override
public WatchService newWatchService() {
this.checker.check();
Expand All @@ -1186,7 +1327,6 @@ public WatchService newWatchService() {
return new MemoryFileSystemWatchService(this);
}


void register(MemoryWatchKey watchKey) {
this.checker.check();
AbsolutePath absolutePath = (AbsolutePath) watchKey.watchable().toAbsolutePath();
Expand All @@ -1201,7 +1341,6 @@ void register(MemoryWatchKey watchKey) {
keys.add(watchKey);
}


FileStore getFileStore() {
return this.store;
}
Expand Down

0 comments on commit 71d44b7

Please sign in to comment.