Skip to content

Commit

Permalink
feat(starter): Issue 31030 issue with symbolic link created with post…
Browse files Browse the repository at this point in the history
…start (#31109)

## Proposed Changes
This pull request includes several updates to the backup directory
configuration and improvements to the `ImportStarterUtil` class for
handling file operations more robustly. The most significant changes are
the introduction of a configurable backup directory path, enhancements
to file handling in `ImportStarterUtil`, and updates to the
`dotmarketing-config.properties` file.

### Backup Directory Configuration:
* Added a method to retrieve a configurable backup directory path with a
default fallback.

### File Handling Improvements:
* Refactored the `deleteTempFiles` method to use Java NIO for better
file handling and safety.
* Enhanced the `validateZipFile` method to ensure proper setup using
Java NIO features and added concurrency safety.

## Fixes
#31030
  • Loading branch information
dcolina authored Jan 15, 2025
1 parent ef325bf commit 2653b71
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 32 deletions.
9 changes: 8 additions & 1 deletion dotCMS/src/main/java/com/dotmarketing/util/ConfigUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;


/**
Expand All @@ -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<String> classesWithIdentity = new ArrayList<>();
private Map<String, String> sequences;
private Map<String, String> tableIDColumns;
Expand Down Expand Up @@ -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);
}
}


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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 2653b71

Please sign in to comment.