Skip to content

Commit

Permalink
Move file utils to SafeFiles class
Browse files Browse the repository at this point in the history
  • Loading branch information
octylFractal committed Mar 25, 2020
1 parent 2b23c2a commit 3b32e67
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.sk89q.worldedit.util.io.file;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class SafeFiles {

/**
* A version of {@link Files#list(Path)} that won't leak resources.
*
* <p>
* Instead, it immediately consumes the entire listing into a {@link List} and
* calls {@link List#stream()}.
* </p>
*
* @param dir the directory to list
* @return an I/O-resource-free stream of the files in the directory
* @throws IOException if an I/O error occurs
*/
public static Stream<Path> noLeakFileList(Path dir) throws IOException {
try (Stream<Path> stream = Files.list(dir)) {
return stream.collect(Collectors.toList()).stream();
}
}

/**
* {@link Path#getFileName()} includes a slash sometimes for some reason.
* This will get rid of it.
*
* @param path the path to get the file name for
* @return the file name of the given path
*/
public static String canonicalFileName(Path path) {
return dropSlash(path.getFileName().toString());
}

private static String dropSlash(String name) {
if (name.isEmpty() || name.codePointBefore(name.length()) != '/') {
return name;
}
return name.substring(0, name.length() - 1);
}

private SafeFiles() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.sk89q.worldedit.util.io.file.ArchiveDir;
import com.sk89q.worldedit.util.io.file.ArchiveNioSupport;
import com.sk89q.worldedit.util.io.file.MorePaths;
import com.sk89q.worldedit.util.io.file.SafeFiles;
import com.sk89q.worldedit.util.time.FileNameDateTimeParser;
import com.sk89q.worldedit.util.time.ModificationDateTimeParser;
import com.sk89q.worldedit.util.time.SnapshotDateTimeParser;
Expand All @@ -45,7 +46,6 @@
import java.util.Objects;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.google.common.base.Preconditions.checkArgument;
Expand Down Expand Up @@ -194,12 +194,6 @@ private Optional<Snapshot> tryRegularFileSnapshot(Path idPath) throws IOExceptio
}
}

private static Stream<Path> noLeakFileList(Path dir) throws IOException {
try (Stream<Path> stream = Files.list(dir)) {
return stream.collect(Collectors.toList()).stream();
}
}

@Override
public Stream<Snapshot> getSnapshots(String worldName) throws IOException {
/*
Expand All @@ -219,13 +213,13 @@ public Stream<Snapshot> getSnapshots(String worldName) throws IOException {
minus the extensions. Due to extension detection methods, this won't work properly
with some files, e.g. world.qux.zip/world.qux is invalid, but world.qux.zip/world isn't.
*/
return noLeakFileList(root)
return SafeFiles.noLeakFileList(root)
.flatMap(IOFunction.unchecked(entry -> {
String worldEntry = getWorldEntry(worldName, entry);
if (worldEntry != null) {
return Stream.of(worldEntry);
}
String fileName = canonicalFileName(entry);
String fileName = SafeFiles.canonicalFileName(entry);
if (fileName.equals(worldName)
&& Files.isDirectory(entry)
&& !Files.exists(entry.resolve("level.dat"))) {
Expand All @@ -244,7 +238,7 @@ public Stream<Snapshot> getSnapshots(String worldName) throws IOException {
}

private Stream<String> listTimestampedEntries(String worldName, Path directory) throws IOException {
return noLeakFileList(directory)
return SafeFiles.noLeakFileList(directory)
.flatMap(IOFunction.unchecked(entry -> getTimestampedEntries(worldName, entry)));
}

Expand All @@ -254,7 +248,7 @@ private Stream<String> getTimestampedEntries(String worldName, Path entry) throw
// nothing available at this path
return Stream.of();
}
String fileName = canonicalFileName(entry);
String fileName = SafeFiles.canonicalFileName(entry);
if (Files.isDirectory(entry)) {
// timestamped directory, find worlds inside
return listWorldEntries(worldName, entry)
Expand All @@ -276,13 +270,13 @@ private Stream<String> getTimestampedEntries(String worldName, Path entry) throw
}

private Stream<String> listWorldEntries(String worldName, Path directory) throws IOException {
return noLeakFileList(directory)
return SafeFiles.noLeakFileList(directory)
.map(IOFunction.unchecked(entry -> getWorldEntry(worldName, entry)))
.filter(Objects::nonNull);
}

private String getWorldEntry(String worldName, Path entry) throws IOException {
String fileName = canonicalFileName(entry);
String fileName = SafeFiles.canonicalFileName(entry);
if (fileName.equals(worldName) && Files.exists(entry.resolve("level.dat"))) {
// world directory
return worldName;
Expand All @@ -298,15 +292,4 @@ private String getWorldEntry(String worldName, Path entry) throws IOException {
return null;
}

private static String canonicalFileName(Path path) {
return dropSlash(path.getFileName().toString());
}

private static String dropSlash(String name) {
if (name.isEmpty() || name.codePointBefore(name.length()) != '/') {
return name;
}
return name.substring(0, name.length() - 1);
}

}

0 comments on commit 3b32e67

Please sign in to comment.