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 org.springframework.lang.NonNull;
 | 
			
		||||
import org.springframework.lang.Nullable;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
import run.halo.app.exception.ForbiddenException;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -11,6 +12,7 @@ import java.io.InputStream;
 | 
			
		|||
import java.nio.file.*;
 | 
			
		||||
import java.nio.file.attribute.BasicFileAttributes;
 | 
			
		||||
import java.util.Comparator;
 | 
			
		||||
import java.util.zip.ZipEntry;
 | 
			
		||||
import java.util.zip.ZipInputStream;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -68,6 +70,86 @@ public class FileUtils {
 | 
			
		|||
                .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.
 | 
			
		||||
     *
 | 
			
		||||
| 
						 | 
				
			
			@ -105,18 +187,28 @@ public class FileUtils {
 | 
			
		|||
        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 {
 | 
			
		||||
            if (inputStream != null) {
 | 
			
		||||
                inputStream.close();
 | 
			
		||||
            }
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            // 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 {
 | 
			
		||||
            if (zipInputStream != null) {
 | 
			
		||||
                zipInputStream.closeEntry();
 | 
			
		||||
| 
						 | 
				
			
			@ -124,7 +216,22 @@ public class FileUtils {
 | 
			
		|||
            }
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            // 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