Feat[cc]: unified place for checking directories and parent directories

This commit is contained in:
artdeell 2023-12-16 18:13:04 +03:00 committed by Maksim Belov
parent 1842e09a6a
commit 87ec536112
7 changed files with 89 additions and 120 deletions

View File

@ -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");

View File

@ -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);
}

View File

@ -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();

View File

@ -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();
}

View File

@ -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> T downloadStringCached(String url, String cacheName, ParseCallback<T> 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> T ensureSha1(File outputFile, @Nullable String sha1, Callable<T> downloadFunction) throws IOException {
// Skip if needed
if(sha1 == null){

View File

@ -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);
}
}

View File

@ -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);
}
}