From 87ec53611239bdde599b40e92a8b179dc241426e Mon Sep 17 00:00:00 2001 From: artdeell Date: Sat, 16 Dec 2023 18:13:04 +0300 Subject: [PATCH] Feat[cc]: unified place for checking directories and parent directories --- .../net/kdt/pojavlaunch/PojavApplication.java | 6 +- .../main/java/net/kdt/pojavlaunch/Tools.java | 12 +- .../modloaders/FabriclikeDownloadTask.java | 4 +- .../kdt/pojavlaunch/multirt/MultiRTUtils.java | 15 +-- .../kdt/pojavlaunch/utils/DownloadUtils.java | 105 ++++-------------- .../net/kdt/pojavlaunch/utils/FileUtils.java | 60 +++++++++- .../net/kdt/pojavlaunch/utils/ZipUtils.java | 7 +- 7 files changed, 89 insertions(+), 120 deletions(-) diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavApplication.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavApplication.java index 71822ba1a..9ca55798a 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavApplication.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavApplication.java @@ -21,6 +21,7 @@ import java.util.concurrent.TimeUnit; import net.kdt.pojavlaunch.lifecycle.ContextExecutor; import net.kdt.pojavlaunch.tasks.AsyncAssetManager; import net.kdt.pojavlaunch.utils.*; +import net.kdt.pojavlaunch.utils.FileUtils; public class PojavApplication extends Application { public static final String CRASH_REPORT_TAG = "PojavCrashReport"; @@ -35,10 +36,7 @@ public class PojavApplication extends Application { File crashFile = new File(storagePermAllowed ? Tools.DIR_GAME_HOME : Tools.DIR_DATA, "latestcrash.txt"); try { // Write to file, since some devices may not able to show error - File crashHome = crashFile.getParentFile(); - if(crashHome != null && !crashHome.exists() && !crashHome.mkdirs()) { - throw new IOException("Failed to create crash log home"); - } + FileUtils.ensureParentDirectory(crashFile); PrintStream crashStream = new PrintStream(crashFile); crashStream.append("PojavLauncher crash report\n"); crashStream.append(" - Time: ").append(DateFormat.getDateTimeInstance().format(new Date())).append("\n"); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java index de5aeb689..90fe12a02 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java @@ -57,6 +57,7 @@ import net.kdt.pojavlaunch.plugins.FFmpegPlugin; import net.kdt.pojavlaunch.prefs.LauncherPreferences; import net.kdt.pojavlaunch.utils.DateUtils; import net.kdt.pojavlaunch.utils.DownloadUtils; +import net.kdt.pojavlaunch.utils.FileUtils; import net.kdt.pojavlaunch.utils.JREUtils; import net.kdt.pojavlaunch.utils.JSONUtils; import net.kdt.pojavlaunch.utils.OldVersionsUtils; @@ -242,7 +243,7 @@ public final class Tools { } public static void disableSplash(File dir) { File configDir = new File(dir, "config"); - if(configDir.exists() || configDir.mkdirs()) { + if(FileUtils.ensureDirectorySilently(configDir)) { File forgeSplashFile = new File(dir, "config/splash.properties"); String forgeSplashContent = "enabled=true"; try { @@ -536,9 +537,7 @@ public final class Tools { public static void copyAssetFile(Context ctx, String fileName, String output, String outputName, boolean overwrite) throws IOException { File parentFolder = new File(output); - if(!parentFolder.exists() && !parentFolder.mkdirs()) { - throw new IOException("Failed to create parent directory"); - } + FileUtils.ensureDirectory(parentFolder); File destinationFile = new File(output, outputName); if(!destinationFile.exists() || overwrite){ try(InputStream inputStream = ctx.getAssets().open(fileName)) { @@ -859,10 +858,7 @@ public final class Tools { public static void write(String path, String content) throws IOException { File file = new File(path); - File parent = file.getParentFile(); - if(parent != null && !parent.exists()) { - if(!parent.mkdirs()) throw new IOException("Failed to create parent directory"); - } + FileUtils.ensureParentDirectory(file); try(FileOutputStream outStream = new FileOutputStream(file)) { IOUtils.write(content, outStream); } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/FabriclikeDownloadTask.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/FabriclikeDownloadTask.java index 706acbce3..a55ea12ff 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/FabriclikeDownloadTask.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/FabriclikeDownloadTask.java @@ -6,6 +6,7 @@ import net.kdt.pojavlaunch.R; import net.kdt.pojavlaunch.Tools; import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper; import net.kdt.pojavlaunch.utils.DownloadUtils; +import net.kdt.pojavlaunch.utils.FileUtils; import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles; import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile; @@ -53,8 +54,7 @@ public class FabriclikeDownloadTask implements Runnable, Tools.DownloaderFeedbac } File versionJsonDir = new File(Tools.DIR_HOME_VERSION, versionId); File versionJsonFile = new File(versionJsonDir, versionId+".json"); - if(versionJsonDir.isFile()) throw new IOException("Version destination directory is a file!"); - if(!versionJsonDir.exists() && !versionJsonDir.mkdirs()) throw new IOException("Failed to create version directory"); + FileUtils.ensureDirectory(versionJsonDir); Tools.write(versionJsonFile.getAbsolutePath(), fabricJson); if(mCreateProfile) { LauncherProfiles.load(); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/multirt/MultiRTUtils.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/multirt/MultiRTUtils.java index 76ea8b1f0..7d008b3f0 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/multirt/MultiRTUtils.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/multirt/MultiRTUtils.java @@ -10,7 +10,6 @@ import com.kdt.mcgui.ProgressLayout; import net.kdt.pojavlaunch.R; import net.kdt.pojavlaunch.Tools; -import net.kdt.pojavlaunch.utils.JREUtils; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; @@ -224,8 +223,7 @@ public class MultiRTUtils { } private static void uncompressTarXZ(final InputStream tarFileInputStream, final File dest) throws IOException { - if(dest.isFile()) throw new IOException("Attempting to unpack into a file"); - if(!dest.exists() && !dest.mkdirs()) throw new IOException("Failed to create destination directory"); + net.kdt.pojavlaunch.utils.FileUtils.ensureDirectory(dest); byte[] buffer = new byte[8192]; TarArchiveInputStream tarIn = new TarArchiveInputStream( @@ -240,10 +238,8 @@ public class MultiRTUtils { ProgressLayout.setProgress(ProgressLayout.UNPACK_RUNTIME, 100, R.string.global_unpacking, tarEntryName); File destPath = new File(dest, tarEntry.getName()); - File destParent = destPath.getParentFile(); + net.kdt.pojavlaunch.utils.FileUtils.ensureParentDirectory(destPath); if (tarEntry.isSymbolicLink()) { - if(destParent != null && !destParent.exists() && !destParent.mkdirs()) - throw new IOException("Failed to create parent directory for symlink"); try { // android.system.Os // Libcore one support all Android versions @@ -253,16 +249,11 @@ public class MultiRTUtils { } } else if (tarEntry.isDirectory()) { - if(!destPath.exists() && !destPath.mkdirs()) - throw new IOException("Failed to create directory"); + net.kdt.pojavlaunch.utils.FileUtils.ensureDirectory(destPath); } else if (!destPath.exists() || destPath.length() != tarEntry.getSize()) { - if(destParent != null && !destParent.exists() && !destParent.mkdirs()) - throw new IOException("Failed to create parent directory for file"); - FileOutputStream os = new FileOutputStream(destPath); IOUtils.copyLarge(tarIn, os, buffer); os.close(); - } tarEntry = tarIn.getNextTarEntry(); } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/DownloadUtils.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/DownloadUtils.java index 6b4c8cbec..0e281975d 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/DownloadUtils.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/DownloadUtils.java @@ -56,75 +56,37 @@ public class DownloadUtils { } public static void downloadFile(String url, File out) throws IOException { - out.getParentFile().mkdirs(); - File tempOut = File.createTempFile(out.getName(), ".part", out.getParentFile()); - BufferedOutputStream bos = null; - try { - OutputStream bos2 = new BufferedOutputStream(new FileOutputStream(tempOut)); - try { - download(url, bos2); - tempOut.renameTo(out); - if (bos2 != null) { - bos2.close(); - } - if (tempOut.exists()) { - tempOut.delete(); - } - } catch (IOException th2) { - if (bos != null) { - bos.close(); - } - if (tempOut.exists()) { - tempOut.delete(); - } - throw th2; - } - } catch (IOException th3) { - - if (bos != null) { - bos.close(); - } - if (tempOut.exists()) { - tempOut.delete(); - } - throw th3; + FileUtils.ensureParentDirectory(out); + try (FileOutputStream fileOutputStream = new FileOutputStream(out)) { + download(url, fileOutputStream); } } - public static void downloadFileMonitored(String urlInput, String nameOutput, @Nullable byte[] buffer, + public static void downloadFileMonitored(String urlInput, File outputFile, @Nullable byte[] buffer, Tools.DownloaderFeedback monitor) throws IOException { - downloadFileMonitored(urlInput, new File(nameOutput), buffer, monitor); - } - public static void downloadFileMonitored(String urlInput,File outputFile, @Nullable byte[] buffer, - Tools.DownloaderFeedback monitor) throws IOException { - if (!outputFile.exists()) { - outputFile.getParentFile().mkdirs(); - } + FileUtils.ensureParentDirectory(outputFile); HttpURLConnection conn = (HttpURLConnection) new URL(urlInput).openConnection(); InputStream readStr = conn.getInputStream(); - FileOutputStream fos = new FileOutputStream(outputFile); - int cur; - int oval = 0; - int len = conn.getContentLength(); + try (FileOutputStream fos = new FileOutputStream(outputFile)) { + int current; + int overall = 0; + int length = conn.getContentLength(); - if(buffer == null) buffer = new byte[65535]; + if (buffer == null) buffer = new byte[65535]; - while ((cur = readStr.read(buffer)) != -1) { - oval += cur; - fos.write(buffer, 0, cur); - monitor.updateProgress(oval, len); + while ((current = readStr.read(buffer)) != -1) { + overall += current; + fos.write(buffer, 0, current); + monitor.updateProgress(overall, length); + } + conn.disconnect(); } - fos.close(); - conn.disconnect(); + } public static T downloadStringCached(String url, String cacheName, ParseCallback parseCallback) throws IOException, ParseException{ File cacheDestination = new File(Tools.DIR_CACHE, "string_cache/"+cacheName); - File cacheDestinationDir = cacheDestination.getParentFile(); - if(cacheDestinationDir != null && - !cacheDestinationDir.exists() && - !cacheDestinationDir.mkdirs()) throw new IOException("Failed to create the cache directory"); if(cacheDestination.isFile() && cacheDestination.canRead() && System.currentTimeMillis() < (cacheDestination.lastModified() + 86400000)) { @@ -143,14 +105,13 @@ public class DownloadUtils { // string into cache T parseResult = parseCallback.process(urlContent); - boolean tryWriteCache = false; + boolean tryWriteCache; if(cacheDestination.exists()) { tryWriteCache = cacheDestination.canWrite(); } else { - // if it is null, then cacheDestination is the file system root. Very bad. - // but let's shield ourselves and just never try to cache the file if that happens - if(cacheDestinationDir != null && !cacheDestinationDir.isFile()) tryWriteCache = cacheDestinationDir.canWrite(); + tryWriteCache = FileUtils.ensureParentDirectorySilently(cacheDestination); } + if(tryWriteCache) try { Tools.write(cacheDestination.getAbsolutePath(), urlContent); }catch(IOException e) { @@ -159,32 +120,6 @@ public class DownloadUtils { return parseResult; } - public static void downloadFileMonitoredWithHeaders(String urlInput,File outputFile, @Nullable byte[] buffer, - Tools.DownloaderFeedback monitor, String userAgent, String cookies) throws IOException { - if (!outputFile.exists()) { - outputFile.getParentFile().mkdirs(); - } - - HttpURLConnection conn = (HttpURLConnection) new URL(urlInput).openConnection(); - conn.setRequestProperty("User-Agent", userAgent); - conn.setRequestProperty("Cookies", cookies); - InputStream readStr = conn.getInputStream(); - FileOutputStream fos = new FileOutputStream(outputFile); - int cur; - int oval = 0; - int len = conn.getContentLength(); - - if(buffer == null) buffer = new byte[65535]; - - while ((cur = readStr.read(buffer)) != -1) { - oval += cur; - fos.write(buffer, 0, cur); - monitor.updateProgress(oval, len); - } - fos.close(); - conn.disconnect(); - } - public static T ensureSha1(File outputFile, @Nullable String sha1, Callable downloadFunction) throws IOException { // Skip if needed if(sha1 == null){ diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/FileUtils.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/FileUtils.java index 2256c6cc5..083ca3f01 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/FileUtils.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/FileUtils.java @@ -1,20 +1,72 @@ package net.kdt.pojavlaunch.utils; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; public class FileUtils { + /** + * Check if a file denoted by a String path exists. + * @param filePath the path to check + * @return whether it exists (same as File.exists() + */ public static boolean exists(String filePath){ return new File(filePath).exists(); } + /** + * Get the file name from a path/URL string. + * @param pathOrUrl the path or the URL of the file + * @return the file's name + */ public static String getFileName(String pathOrUrl) { int lastSlashIndex = pathOrUrl.lastIndexOf('/'); if(lastSlashIndex == -1) return null; return pathOrUrl.substring(lastSlashIndex); } + + /** + * Ensure that a directory exists, is a directory and is writable. + * @param targetFile the directory to check + * @return if the check has succeeded + */ + public static boolean ensureDirectorySilently(File targetFile) { + if(targetFile.isFile()) return false; + if(targetFile.exists()) return targetFile.canWrite(); + else return targetFile.mkdirs(); + + } + + /** + * Ensure that the parent directory of a file exists and is writable + * @param targetFile the File whose parent should be checked + * @return if the check as succeeded + */ + public static boolean ensureParentDirectorySilently(File targetFile) { + File parentFile = targetFile.getParentFile(); + if(parentFile == null) return false; + return ensureDirectorySilently(parentFile); + } + + /** + * Same as ensureDirectorySilently(), but throws an IOException telling why the check failed. + * @param targetFile the directory to check + * @throws IOException when the checks fail + */ + public static void ensureDirectory(File targetFile) throws IOException{ + if(targetFile.isFile()) throw new IOException("Target directory is a file"); + if(targetFile.exists()) { + if(!targetFile.canWrite()) throw new IOException("Target directory is not writable"); + }else if(!targetFile.mkdirs()) throw new IOException("Unable to create target directory"); + } + + /** + * Same as ensureParentDirectorySilently(), but throws an IOException telling why the check failed. + * @param targetFile the File whose parent should be checked + * @throws IOException when the checks fail + */ + public static void ensureParentDirectory(File targetFile) throws IOException{ + File parentFile = targetFile.getParentFile(); + if(parentFile == null) throw new IOException("targetFile does not have a parent"); + ensureDirectory(parentFile); + } } \ No newline at end of file diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/ZipUtils.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/ZipUtils.java index a56fd661b..91247aa1e 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/ZipUtils.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/ZipUtils.java @@ -45,12 +45,9 @@ public class ZipUtils { String entryName = zipEntry.getName(); if(!entryName.startsWith(dirName) || zipEntry.isDirectory()) continue; File zipDestination = new File(destination, entryName.substring(dirNameLen)); - File parent = zipDestination.getParentFile(); - if(parent != null && !parent.exists()) - if(!parent.mkdirs()) throw new IOException("Failed to create "+parent.getAbsolutePath()); + FileUtils.ensureParentDirectory(zipDestination); try (InputStream inputStream = zipFile.getInputStream(zipEntry); - OutputStream outputStream = - new FileOutputStream(zipDestination)) { + OutputStream outputStream = new FileOutputStream(zipDestination)) { IOUtils.copy(inputStream, outputStream); } }