mirror of https://github.com/halo-dev/halo
Add some useful features to FileUtils
parent
3d17e0f786
commit
ef417a2c14
|
@ -2,6 +2,7 @@ package run.halo.app.utils;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import run.halo.app.exception.ForbiddenException;
|
import run.halo.app.exception.ForbiddenException;
|
||||||
|
|
||||||
|
@ -11,6 +12,7 @@ import java.io.InputStream;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,6 +70,86 @@ public class FileUtils {
|
||||||
.forEach(File::delete);
|
.forEach(File::delete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unzip content to the target path.
|
||||||
|
*
|
||||||
|
* @param zis zip input stream must not be null
|
||||||
|
* @param targetPath target path must not be null and not empty
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static void unzip(@NonNull ZipInputStream zis, @NonNull Path targetPath) throws IOException {
|
||||||
|
Assert.notNull(zis, "Zip input stream must not be null");
|
||||||
|
Assert.notNull(targetPath, "Target path must not be null");
|
||||||
|
|
||||||
|
// Create path if absent
|
||||||
|
createIfAbsent(targetPath);
|
||||||
|
|
||||||
|
// Must be empty
|
||||||
|
mustBeEmpty(targetPath);
|
||||||
|
|
||||||
|
ZipEntry zipEntry = zis.getNextEntry();
|
||||||
|
|
||||||
|
while (zipEntry != null) {
|
||||||
|
// Resolve the entry path
|
||||||
|
Path entryPath = targetPath.resolve(zipEntry.getName());
|
||||||
|
|
||||||
|
// Check directory
|
||||||
|
FileUtils.checkDirectoryTraversal(targetPath, entryPath);
|
||||||
|
|
||||||
|
if (zipEntry.isDirectory()) {
|
||||||
|
// Create directories
|
||||||
|
Files.createDirectories(entryPath);
|
||||||
|
} else {
|
||||||
|
// Copy file
|
||||||
|
Files.copy(zis, entryPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
zipEntry = zis.getNextEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates directories if absent.
|
||||||
|
*
|
||||||
|
* @param path path must not be null
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static void createIfAbsent(@NonNull Path path) throws IOException {
|
||||||
|
Assert.notNull(path, "Path must not be null");
|
||||||
|
|
||||||
|
if (Files.notExists(path)) {
|
||||||
|
// Create directories
|
||||||
|
Files.createDirectories(path);
|
||||||
|
|
||||||
|
log.debug("Created directory: [{}]", path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given path is empty.
|
||||||
|
*
|
||||||
|
* @param path path must not be null
|
||||||
|
* @return true if the given path is empty; false otherwise
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static boolean isEmpty(@NonNull Path path) throws IOException {
|
||||||
|
Assert.notNull(path, "Path must not be null");
|
||||||
|
|
||||||
|
return Files.list(path).count() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The given path must be empty.
|
||||||
|
*
|
||||||
|
* @param path path must not be null
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static void mustBeEmpty(@NonNull Path path) throws IOException {
|
||||||
|
if (!isEmpty(path)) {
|
||||||
|
throw new DirectoryNotEmptyException("Target directory: " + path + " was not empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks directory traversal vulnerability.
|
* Checks directory traversal vulnerability.
|
||||||
*
|
*
|
||||||
|
@ -105,18 +187,28 @@ public class FileUtils {
|
||||||
throw new ForbiddenException("You cannot access " + pathToCheck).setErrorData(pathToCheck);
|
throw new ForbiddenException("You cannot access " + pathToCheck).setErrorData(pathToCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void closeQuietly(InputStream inputStream) {
|
/**
|
||||||
|
* Closes input stream quietly.
|
||||||
|
*
|
||||||
|
* @param inputStream input stream
|
||||||
|
*/
|
||||||
|
public static void closeQuietly(@Nullable InputStream inputStream) {
|
||||||
try {
|
try {
|
||||||
if (inputStream != null) {
|
if (inputStream != null) {
|
||||||
inputStream.close();
|
inputStream.close();
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Ignore this exception
|
// Ignore this exception
|
||||||
log.error("Failed to close input stream", e);
|
log.warn("Failed to close input stream", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void closeQuietly(ZipInputStream zipInputStream) {
|
/**
|
||||||
|
* Closes zip input stream quietly.
|
||||||
|
*
|
||||||
|
* @param zipInputStream zip input stream
|
||||||
|
*/
|
||||||
|
public static void closeQuietly(@Nullable ZipInputStream zipInputStream) {
|
||||||
try {
|
try {
|
||||||
if (zipInputStream != null) {
|
if (zipInputStream != null) {
|
||||||
zipInputStream.closeEntry();
|
zipInputStream.closeEntry();
|
||||||
|
@ -124,7 +216,22 @@ public class FileUtils {
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Ignore this exception
|
// Ignore this exception
|
||||||
log.error("Failed to close zip input stream", e);
|
log.warn("Failed to close zip input stream", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes folder quietly.
|
||||||
|
*
|
||||||
|
* @param deletingPath deleting path must not be null
|
||||||
|
*/
|
||||||
|
public static void deleteFolderQuietly(@NonNull Path deletingPath) {
|
||||||
|
try {
|
||||||
|
if (deletingPath != null) {
|
||||||
|
FileUtils.deleteFolder(deletingPath);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Failed to delete " + deletingPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue