diff --git a/dotCMS/src/main/java/com/dotmarketing/util/ConfigUtils.java b/dotCMS/src/main/java/com/dotmarketing/util/ConfigUtils.java index e0509a5a5c4c..7436ce9d16e0 100644 --- a/dotCMS/src/main/java/com/dotmarketing/util/ConfigUtils.java +++ b/dotCMS/src/main/java/com/dotmarketing/util/ConfigUtils.java @@ -68,10 +68,17 @@ public static String getLucenePath() { return getDynamicContentPath() + File.separator + "dotlucene"; } + /** + * Retrieves the configurable path for the backup directory. + * Defaults to DYNAMIC_CONTENT_PATH/dotsecure/backup if not overridden. + * + * @return the backup directory path + */ public static String getBackupPath() { - return getDynamicContentPath() + File.separator + "backup"; + return Config.getStringProperty("BACKUP_DIRECTORY_PATH", getDynamicContentPath() + File.separator + "backup"); } + public static String getBundlePath() { final Path path = Paths.get(String.format("%s%sbundles",getAbsoluteAssetsRootPath(),File.separator)).normalize(); File pathDir = path.toFile(); diff --git a/dotCMS/src/main/java/com/dotmarketing/util/starter/ImportStarterUtil.java b/dotCMS/src/main/java/com/dotmarketing/util/starter/ImportStarterUtil.java index ce7be09abbf4..a9ee99baf9e9 100644 --- a/dotCMS/src/main/java/com/dotmarketing/util/starter/ImportStarterUtil.java +++ b/dotCMS/src/main/java/com/dotmarketing/util/starter/ImportStarterUtil.java @@ -1,8 +1,5 @@ package com.dotmarketing.util.starter; -import static com.dotcms.util.ConversionUtils.toLong; -import static com.dotmarketing.util.ConfigUtils.getDeclaredDefaultLanguage; - import com.dotcms.business.WrapInTransaction; import com.dotcms.content.business.json.ContentletJsonHelper; import com.dotcms.contenttype.model.field.DataTypes; @@ -61,13 +58,14 @@ import com.liferay.util.FileUtil; import io.vavr.Tuple2; import io.vavr.control.Try; +import org.apache.commons.beanutils.BeanUtils; + import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.nio.channels.WritableByteChannel; import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; @@ -83,7 +81,9 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.zip.ZipFile; -import org.apache.commons.beanutils.BeanUtils; + +import static com.dotcms.util.ConversionUtils.toLong; +import static com.dotmarketing.util.ConfigUtils.getDeclaredDefaultLanguage; /** @@ -99,9 +99,10 @@ public class ImportStarterUtil { /** - * The path where tmp files are stored. This gets wiped alot + * Fully configurable path for the backup directory. */ - private String backupTempFilePath = ConfigUtils.getBackupPath() + File.separator + "temp"; + private static final String BACKUP_DIRECTORY = ConfigUtils.getBackupPath(); + private String backupTempFilePath = BACKUP_DIRECTORY + File.separator + "temp"; private ArrayList classesWithIdentity = new ArrayList<>(); private Map sequences; private Map tableIDColumns; @@ -399,9 +400,17 @@ private void copyAssetDir() throws IOException { * Deletes all files from the backupTempFilePath */ private void deleteTempFiles() { - File f = new File(backupTempFilePath); - - FileUtil.deltree(f, true); + try { + Path tempDir = Paths.get(getBackupTempFilePath()); + if (Files.exists(tempDir)) { + Files.walk(tempDir) + .sorted(Comparator.reverseOrder()) + .map(Path::toFile) + .forEach(File::delete); + } + } catch (IOException e) { + Logger.error(this, "Error cleaning up temp files", e); + } } @@ -930,41 +939,45 @@ public void setBackupTempFilePath(String backupTempFilePath) { } /** + * Validates the zip file and ensures proper setup using Java NIO features. + * Handles directory creation safely and ensures concurrency safety. * - * @return + * @return true if the zip file is valid and successfully processed. */ public boolean validateZipFile() { - String tempdir = getBackupTempFilePath(); + String tempDirPath = getBackupTempFilePath(); if (starterZip == null || !starterZip.exists()) { - throw new DotStateException("Starter.zip does not exist:" + starterZip); + throw new DotStateException("Starter.zip does not exist: " + starterZip); } try { + // Clean up temp directory before processing deleteTempFiles(); - File ftempDir = new File(tempdir); - ftempDir.mkdirs(); - File tempZip = new File(tempdir + File.separator + starterZip.getName()); - tempZip.createNewFile(); + Path tempDir = Paths.get(tempDirPath); - try (final ReadableByteChannel inputChannel = Channels.newChannel(Files.newInputStream(starterZip.toPath())); - final WritableByteChannel outputChannel = - Channels.newChannel(Files.newOutputStream(tempZip.toPath()))) { + // Create the temp directory if it does not exist - FileUtil.fastCopyUsingNio(inputChannel, outputChannel); + if (!Files.exists(tempDir)) { + Files.createDirectories(tempDir); + } else if (!Files.isDirectory(tempDir)) { + throw new DotRuntimeException("Backup path exists but is not a directory: " + backupTempFilePath); } - /* - * Unzip zipped backups - */ - if (starterZip != null && starterZip.getName().toLowerCase().endsWith(".zip")) { - ZipFile z = new ZipFile(starterZip); - ZipUtil.extract(z, new File(backupTempFilePath)); + // Extract the zip file contents into the temp directory + if (starterZip.getName().toLowerCase().endsWith(".zip")) { + try (ZipFile zipFile = new ZipFile(starterZip)) { + ZipUtil.extract(zipFile, tempDir.toFile()); + } } + + // Process the extracted contents (if needed) + Logger.info(this, String.format("Successfully processed starter.zip in: %s", tempDir)); + return true; - } catch (Exception e) { - throw new DotStateException("Starter.zip invalid:" + e.getMessage(), e); + } catch (IOException e) { + throw new DotStateException("Error processing starter.zip: " + e.getMessage(), e); } } diff --git a/dotcms-integration/src/test/resources/dotmarketing-config.properties b/dotcms-integration/src/test/resources/dotmarketing-config.properties index b991d44ef6c4..73d739699706 100644 --- a/dotcms-integration/src/test/resources/dotmarketing-config.properties +++ b/dotcms-integration/src/test/resources/dotmarketing-config.properties @@ -86,6 +86,8 @@ DEFAULT_REFERER = /index.jsp VERSION_FILE_PREFIX = /dotVersion SAVED_UPLOAD_FILES_PATH = /uploaded_files +## This is the path where the backup files will be stored. Defaults to DYNAMIC_CONTENT_PATH/dotsecure/backup if not set. +# BACKUP_DIRECTORY_PATH= ## This controls when content can be added to pages, if set true then the user will only ## required add children permissions to add content to a page if set to false then the