From 487f1881baa7aa843873eb1723c8fdc75b76e4f6 Mon Sep 17 00:00:00 2001
From: abobrov <abobrov@localhost>
Date: Fri, 19 Dec 2008 14:31:30 +0000
Subject: [PATCH] - [Issue 3674] Task backend should support backup and export
---
opendj-sdk/opends/src/messages/messages/backend.properties | 77 +++++
opendj-sdk/opends/src/server/org/opends/server/types/LDIFExportConfig.java | 20
opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskBackend.java | 771 +++++++++++++++++++++++++++++++++++++++++++++++++++
opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java | 8
4 files changed, 862 insertions(+), 14 deletions(-)
diff --git a/opendj-sdk/opends/src/messages/messages/backend.properties b/opendj-sdk/opends/src/messages/messages/backend.properties
index 48e4025..b39b2fb 100644
--- a/opendj-sdk/opends/src/messages/messages/backend.properties
+++ b/opendj-sdk/opends/src/messages/messages/backend.properties
@@ -1056,3 +1056,80 @@
SEVERE_ERR_RECURRINGTASK_INVALID_TOKENS_COMBO_377=The provided recurring task \
entry attribute %s holding the recurring task schedule has invalid tokens \
combination yielding a nonexistent calendar date
+SEVERE_ERR_TASKS_CANNOT_EXPORT_TO_FILE_378=An error occurred while \
+ attempting to export task backend data: %s
+SEVERE_ERR_TASKS_BACKUP_CANNOT_GET_MAC_379=An error occurred while attempting \
+ to obtain the %s MAC provider to create the signed hash for the backup: %s
+SEVERE_ERR_TASKS_BACKUP_CANNOT_GET_DIGEST_380=An error occurred while \
+ attempting to obtain the %s message digest to create the hash for the backup: \
+ %s
+SEVERE_ERR_TASKS_BACKUP_CANNOT_CREATE_ARCHIVE_FILE_381=An error occurred \
+ while trying to create the tasks archive file %s in directory %s: %s
+SEVERE_ERR_TASKS_BACKUP_CANNOT_GET_CIPHER_382=An error occurred while \
+ attempting to obtain the cipher to use to encrypt the backup: %s
+SEVERE_ERR_TASKS_BACKUP_ZIP_COMMENT_383=%s tasks backup %s
+SEVERE_ERR_TASKS_BACKUP_CANNOT_BACKUP_TASKS_FILE_384=An error occurred while \
+ attempting to back up tasks file %s: %s
+SEVERE_ERR_TASKS_BACKUP_CANNOT_CLOSE_ZIP_STREAM_385=An error occurred while \
+ trying to close the tasks archive file %s in directory %s: %s
+SEVERE_ERR_TASKS_BACKUP_CANNOT_UPDATE_BACKUP_DESCRIPTOR_386=An error occurred \
+ while attempting to update the backup descriptor file %s with information \
+ about the tasks backup: %s
+SEVERE_ERR_TASKS_RESTORE_NO_SUCH_BACKUP_387=Unable to restore or verify \
+ tasks backup %s in directory %s because no such backup exists
+SEVERE_ERR_TASKS_RESTORE_NO_BACKUP_FILE_388=Unable to restore or verify \
+ tasks backup %s in directory %s because the archive filename could not be \
+ determined
+SEVERE_ERR_TASKS_RESTORE_NO_SUCH_FILE_389=Unable to restore or verify tasks \
+ backup %s because the specified archive file %s does not exist
+SEVERE_ERR_TASKS_RESTORE_CANNOT_CHECK_FOR_ARCHIVE_390=Unable to restore or \
+ verify tasks backup %s because an error occurred while trying to determine \
+ whether backup archive %s exists: %s
+SEVERE_ERR_TASKS_RESTORE_UNKNOWN_DIGEST_391=Unable to restore or verify \
+ tasks backup %s because an unsigned hash of this backup is available but the \
+ server cannot determine the digest algorithm used to generate this hash
+SEVERE_ERR_TASKS_RESTORE_CANNOT_GET_DIGEST_392=Unable to restore or verify \
+ tasks backup %s because it has an unsigned hash that uses an unknown or \
+ unsupported digest algorithm of %s
+SEVERE_ERR_TASKS_RESTORE_UNKNOWN_MAC_393=Unable to restore or verify tasks \
+ backup %s because a signed hash of this backup is available but the server \
+ cannot determine the MAC algorithm used to generate this hash
+SEVERE_ERR_TASKS_RESTORE_CANNOT_GET_MAC_394=Unable to restore or verify \
+ tasks backup %s because it has a signed hash that uses an unknown or \
+ unsupported MAC algorithm of %s
+SEVERE_ERR_TASKS_RESTORE_CANNOT_OPEN_BACKUP_FILE_395=Unable to restore or \
+ verify tasks backup %s because an error occurred while attempting to open \
+ the backup archive file %s: %s
+SEVERE_ERR_TASKS_RESTORE_CANNOT_GET_CIPHER_396=Unable to restore or verify \
+ tasks backup %s because it is encrypted using an unknown or unsupported \
+ cipher: %s
+SEVERE_ERR_TASKS_RESTORE_CANNOT_GET_ZIP_ENTRY_397=Unable to restore or verify \
+ tasks backup %s because an error occurred while trying to read the next \
+ entry from the archive file %s: %s
+SEVERE_ERR_TASKS_RESTORE_CANNOT_CREATE_FILE_398=Unable to restore tasks \
+ backup %s because an error occurred while trying to recreate file %s: %s
+SEVERE_ERR_TASKS_RESTORE_CANNOT_PROCESS_ARCHIVE_FILE_399=Unable to restore or \
+ verify tasks backup %s because an error occurred while processing archived \
+ file %s: %s
+SEVERE_ERR_TASKS_RESTORE_ERROR_ON_ZIP_STREAM_CLOSE_400=Unable to restore or \
+ verify tasks backup %s because an unexpected error occurred while trying to \
+ close the archive file %s: %s
+NOTICE_TASKS_RESTORE_UNSIGNED_HASH_VALID_401=The message digest calculated \
+ from the backup archive matches the digest stored with the backup information
+SEVERE_ERR_TASKS_RESTORE_UNSIGNED_HASH_INVALID_402=Unable to restore or \
+ verify tasks backup %s because the message digest calculated from the backup \
+ archive does not match the digest stored with the backup information
+NOTICE_TASKS_RESTORE_SIGNED_HASH_VALID_403=The signed digest calculated from \
+ the backup archive matches the signature stored with the backup information
+SEVERE_ERR_TASKS_RESTORE_SIGNED_HASH_INVALID_404=Unable to restore or verify \
+ tasks backup %s because the signed digest calculated from the backup archive \
+ does not match the signature stored with the backup information
+NOTICE_TASKS_RESTORE_VERIFY_SUCCESSFUL_405=All tests performed on tasks \
+ backup %s from directory %s show that the archive appears to be valid
+NOTICE_TASKS_RESTORE_SUCCESSFUL_406=Tasks backup %s was successfully \
+ restored from the archive in directory %s
+SEVERE_ERR_BACKUP_MISSING_BACKUPID_407=The information for backup %s could \
+ not be found in the backup directory %s
+SEVERE_ERR_BACKUP_CANNOT_UPDATE_BACKUP_DESCRIPTOR_408=An error occurred \
+ while attempting to update the backup descriptor file %s with information \
+ about the backup: %s
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskBackend.java b/opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskBackend.java
index 6029483..f25ab24 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskBackend.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskBackend.java
@@ -29,13 +29,26 @@
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.net.InetAddress;
+import java.security.MessageDigest;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.locks.Lock;
+import java.util.zip.Deflater;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+import javax.crypto.Mac;
import org.opends.messages.Message;
import org.opends.server.admin.Configuration;
import org.opends.server.admin.server.ConfigurationChangeListener;
@@ -55,9 +68,12 @@
import org.opends.server.types.AttributeValue;
import org.opends.server.types.BackupConfig;
import org.opends.server.types.BackupDirectory;
+import org.opends.server.types.BackupInfo;
import org.opends.server.types.CanceledOperationException;
import org.opends.server.types.ConditionResult;
import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.CryptoManager;
+import org.opends.server.types.CryptoManagerException;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.DN;
@@ -74,12 +90,18 @@
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchFilter;
import org.opends.server.types.SearchScope;
+import org.opends.server.util.DynamicConstants;
+import org.opends.server.util.LDIFException;
+import org.opends.server.util.LDIFReader;
+import org.opends.server.util.LDIFWriter;
import org.opends.server.util.Validator;
import static org.opends.messages.BackendMessages.*;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.util.StaticUtils.*;
+import static org.opends.server.util.ServerConstants.*;
@@ -1131,7 +1153,105 @@
public void exportLDIF(LDIFExportConfig exportConfig)
throws DirectoryException
{
- // FIXME -- Implement support for exporting to LDIF.
+ File taskFile = getFileForPath(taskBackingFile);
+
+ // Read from.
+ LDIFReader ldifReader;
+ try
+ {
+ ldifReader = new LDIFReader(new LDIFImportConfig(taskFile.getPath()));
+ }
+ catch (Exception e)
+ {
+ Message message =
+ ERR_TASKS_CANNOT_EXPORT_TO_FILE.get(String.valueOf(e));
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message, e);
+ }
+
+ // Write to.
+ LDIFWriter ldifWriter;
+ try
+ {
+ ldifWriter = new LDIFWriter(exportConfig);
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ Message message = ERR_TASKS_CANNOT_EXPORT_TO_FILE.get(
+ stackTraceToSingleLineString(e));
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message);
+ }
+
+ // Copy record by record.
+ try
+ {
+ while (true)
+ {
+ Entry e = null;
+ try
+ {
+ e = ldifReader.readEntry();
+ if (e == null)
+ {
+ break;
+ }
+ }
+ catch (LDIFException le)
+ {
+ if (! le.canContinueReading())
+ {
+ Message message =
+ ERR_TASKS_CANNOT_EXPORT_TO_FILE.get(String.valueOf(e));
+ throw new DirectoryException(
+ DirectoryServer.getServerErrorResultCode(),
+ message, le);
+ }
+ else
+ {
+ continue;
+ }
+ }
+ ldifWriter.writeEntry(e);
+ }
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+ }
+ finally
+ {
+ try
+ {
+ ldifWriter.close();
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+ }
+ try
+ {
+ ldifReader.close();
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+ }
+ }
}
@@ -1194,7 +1314,294 @@
public void createBackup(BackupConfig backupConfig)
throws DirectoryException
{
- // NYI -- Create the backup.
+ // Get the properties to use for the backup. We don't care whether or not
+ // it's incremental, so there's no need to get that.
+ String backupID = backupConfig.getBackupID();
+ BackupDirectory backupDirectory = backupConfig.getBackupDirectory();
+ boolean compress = backupConfig.compressData();
+ boolean encrypt = backupConfig.encryptData();
+ boolean hash = backupConfig.hashData();
+ boolean signHash = backupConfig.signHash();
+
+
+ // Create a hash map that will hold the extra backup property information
+ // for this backup.
+ HashMap<String,String> backupProperties = new HashMap<String,String>();
+
+
+ // Get the crypto manager and use it to obtain references to the message
+ // digest and/or MAC to use for hashing and/or signing.
+ CryptoManager cryptoManager = DirectoryServer.getCryptoManager();
+ Mac mac = null;
+ MessageDigest digest = null;
+ String digestAlgorithm = null;
+ String macKeyID = null;
+
+ if (hash)
+ {
+ if (signHash)
+ {
+ try
+ {
+ macKeyID = cryptoManager.getMacEngineKeyEntryID();
+ backupProperties.put(BACKUP_PROPERTY_MAC_KEY_ID, macKeyID);
+
+ mac = cryptoManager.getMacEngine(macKeyID);
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ Message message = ERR_TASKS_BACKUP_CANNOT_GET_MAC.get(
+ macKeyID, stackTraceToSingleLineString(e));
+ throw new DirectoryException(
+ DirectoryServer.getServerErrorResultCode(), message,
+ e);
+ }
+ }
+ else
+ {
+ digestAlgorithm = cryptoManager.getPreferredMessageDigestAlgorithm();
+ backupProperties.put(BACKUP_PROPERTY_DIGEST_ALGORITHM, digestAlgorithm);
+
+ try
+ {
+ digest = cryptoManager.getPreferredMessageDigest();
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ Message message = ERR_TASKS_BACKUP_CANNOT_GET_DIGEST.get(
+ digestAlgorithm, stackTraceToSingleLineString(e));
+ throw new DirectoryException(
+ DirectoryServer.getServerErrorResultCode(), message,
+ e);
+ }
+ }
+ }
+
+
+ // Create an output stream that will be used to write the archive file. At
+ // its core, it will be a file output stream to put a file on the disk. If
+ // we are to encrypt the data, then that file output stream will be wrapped
+ // in a cipher output stream. The resulting output stream will then be
+ // wrapped by a zip output stream (which may or may not actually use
+ // compression).
+ String filename = null;
+ OutputStream outputStream;
+ try
+ {
+ filename = TASKS_BACKUP_BASE_FILENAME + backupID;
+ File archiveFile = new File(backupDirectory.getPath() + File.separator +
+ filename);
+ if (archiveFile.exists())
+ {
+ int i=1;
+ while (true)
+ {
+ archiveFile = new File(backupDirectory.getPath() + File.separator +
+ filename + "." + i);
+ if (archiveFile.exists())
+ {
+ i++;
+ }
+ else
+ {
+ filename = filename + "." + i;
+ break;
+ }
+ }
+ }
+
+ outputStream = new FileOutputStream(archiveFile, false);
+ backupProperties.put(BACKUP_PROPERTY_ARCHIVE_FILENAME, filename);
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ Message message = ERR_TASKS_BACKUP_CANNOT_CREATE_ARCHIVE_FILE.
+ get(String.valueOf(filename), backupDirectory.getPath(),
+ getExceptionMessage(e));
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message, e);
+ }
+
+
+ // If we should encrypt the data, then wrap the output stream in a cipher
+ // output stream.
+ if (encrypt)
+ {
+ try
+ {
+ outputStream
+ = cryptoManager.getCipherOutputStream(outputStream);
+ }
+ catch (CryptoManagerException e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ Message message = ERR_TASKS_BACKUP_CANNOT_GET_CIPHER.get(
+ stackTraceToSingleLineString(e));
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message, e);
+ }
+ }
+
+
+ // Wrap the file output stream in a zip output stream.
+ ZipOutputStream zipStream = new ZipOutputStream(outputStream);
+
+ Message message = ERR_TASKS_BACKUP_ZIP_COMMENT.get(
+ DynamicConstants.PRODUCT_NAME,
+ backupID);
+ zipStream.setComment(String.valueOf(message));
+
+ if (compress)
+ {
+ zipStream.setLevel(Deflater.DEFAULT_COMPRESSION);
+ }
+ else
+ {
+ zipStream.setLevel(Deflater.NO_COMPRESSION);
+ }
+
+ // Take tasks file and write it to the zip stream. If we
+ // are using a hash or MAC, then calculate that as well.
+ byte[] buffer = new byte[8192];
+ File tasksFile = getFileForPath(taskBackingFile);
+ String baseName = tasksFile.getName();
+
+ // We'll put the name in the hash, too.
+ if (hash) {
+ if (signHash) {
+ mac.update(getBytes(baseName));
+ } else {
+ digest.update(getBytes(baseName));
+ }
+ }
+
+ InputStream inputStream = null;
+ try {
+ ZipEntry zipEntry = new ZipEntry(baseName);
+ zipStream.putNextEntry(zipEntry);
+
+ inputStream = new FileInputStream(tasksFile);
+ while (true) {
+ int bytesRead = inputStream.read(buffer);
+ if (bytesRead < 0 || backupConfig.isCancelled()) {
+ break;
+ }
+
+ if (hash) {
+ if (signHash) {
+ mac.update(buffer, 0, bytesRead);
+ } else {
+ digest.update(buffer, 0, bytesRead);
+ }
+ }
+
+ zipStream.write(buffer, 0, bytesRead);
+ }
+
+ zipStream.closeEntry();
+ inputStream.close();
+ } catch (Exception e) {
+ if (debugEnabled()) {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ try {
+ inputStream.close();
+ } catch (Exception e2) {
+ }
+
+ try {
+ zipStream.close();
+ } catch (Exception e2) {
+ }
+
+ message = ERR_TASKS_BACKUP_CANNOT_BACKUP_TASKS_FILE.get(baseName,
+ stackTraceToSingleLineString(e));
+ throw new DirectoryException(
+ DirectoryServer.getServerErrorResultCode(),
+ message, e);
+ }
+
+ // We're done writing the file, so close the zip stream (which should also
+ // close the underlying stream).
+ try
+ {
+ zipStream.close();
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ message = ERR_TASKS_BACKUP_CANNOT_CLOSE_ZIP_STREAM.get(
+ filename, backupDirectory.getPath(), stackTraceToSingleLineString(e));
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message, e);
+ }
+
+
+ // Get the digest or MAC bytes if appropriate.
+ byte[] digestBytes = null;
+ byte[] macBytes = null;
+ if (hash)
+ {
+ if (signHash)
+ {
+ macBytes = mac.doFinal();
+ }
+ else
+ {
+ digestBytes = digest.digest();
+ }
+ }
+
+
+ // Create the backup info structure for this backup and add it to the backup
+ // directory.
+ // FIXME -- Should I use the date from when I started or finished?
+ BackupInfo backupInfo = new BackupInfo(backupDirectory, backupID,
+ new Date(), false, compress,
+ encrypt, digestBytes, macBytes,
+ null, backupProperties);
+
+ try
+ {
+ backupDirectory.addBackup(backupInfo);
+ backupDirectory.writeBackupDirectoryDescriptor();
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ message = ERR_TASKS_BACKUP_CANNOT_UPDATE_BACKUP_DESCRIPTOR.get(
+ backupDirectory.getDescriptorPath(), stackTraceToSingleLineString(e));
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message, e);
+ }
}
@@ -1207,7 +1614,54 @@
String backupID)
throws DirectoryException
{
- // NYI -- Remove the backup.
+ BackupInfo backupInfo = backupDirectory.getBackupInfo(backupID);
+ if (backupInfo == null)
+ {
+ Message message = ERR_BACKUP_MISSING_BACKUPID.get(
+ backupDirectory.getPath(), backupID);
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message);
+ }
+
+ HashMap<String,String> backupProperties = backupInfo.getBackupProperties();
+
+ String archiveFilename =
+ backupProperties.get(BACKUP_PROPERTY_ARCHIVE_FILENAME);
+ File archiveFile = new File(backupDirectory.getPath(), archiveFilename);
+
+ try
+ {
+ backupDirectory.removeBackup(backupID);
+ }
+ catch (ConfigException e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ e.getMessageObject());
+ }
+
+ try
+ {
+ backupDirectory.writeBackupDirectoryDescriptor();
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ Message message = ERR_BACKUP_CANNOT_UPDATE_BACKUP_DESCRIPTOR.get(
+ backupDirectory.getDescriptorPath(), stackTraceToSingleLineString(e));
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message, e);
+ }
+
+ // Remove the archive file.
+ archiveFile.delete();
}
@@ -1231,7 +1685,316 @@
public void restoreBackup(RestoreConfig restoreConfig)
throws DirectoryException
{
- // NYI -- Restore the backup.
+ // First, make sure that the requested backup exists.
+ BackupDirectory backupDirectory = restoreConfig.getBackupDirectory();
+ String backupPath = backupDirectory.getPath();
+ String backupID = restoreConfig.getBackupID();
+ BackupInfo backupInfo = backupDirectory.getBackupInfo(backupID);
+ boolean verifyOnly = restoreConfig.verifyOnly();
+
+ if (backupInfo == null)
+ {
+ Message message =
+ ERR_TASKS_RESTORE_NO_SUCH_BACKUP.get(backupID, backupPath);
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message);
+ }
+
+ // Read the backup info structure to determine the name of the file that
+ // contains the archive. Then make sure that file exists.
+ String backupFilename =
+ backupInfo.getBackupProperty(BACKUP_PROPERTY_ARCHIVE_FILENAME);
+ if (backupFilename == null)
+ {
+ Message message =
+ ERR_TASKS_RESTORE_NO_BACKUP_FILE.get(backupID, backupPath);
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message);
+ }
+
+ File backupFile = new File(backupPath + File.separator + backupFilename);
+ try
+ {
+ if (! backupFile.exists())
+ {
+ Message message =
+ ERR_TASKS_RESTORE_NO_SUCH_FILE.get(backupID, backupFile.getPath());
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message);
+ }
+ }
+ catch (DirectoryException de)
+ {
+ throw de;
+ }
+ catch (Exception e)
+ {
+ Message message = ERR_TASKS_RESTORE_CANNOT_CHECK_FOR_ARCHIVE.get(
+ backupID, backupFile.getPath(), stackTraceToSingleLineString(e));
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message, e);
+ }
+
+ // If the backup is hashed, then we need to get the message digest to use
+ // to verify it.
+ byte[] unsignedHash = backupInfo.getUnsignedHash();
+ MessageDigest digest = null;
+ if (unsignedHash != null)
+ {
+ String digestAlgorithm =
+ backupInfo.getBackupProperty(BACKUP_PROPERTY_DIGEST_ALGORITHM);
+ if (digestAlgorithm == null)
+ {
+ Message message = ERR_TASKS_RESTORE_UNKNOWN_DIGEST.get(backupID);
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message);
+ }
+
+ try
+ {
+ digest = DirectoryServer.getCryptoManager().getMessageDigest(
+ digestAlgorithm);
+ }
+ catch (Exception e)
+ {
+ Message message =
+ ERR_TASKS_RESTORE_CANNOT_GET_DIGEST.get(backupID, digestAlgorithm);
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message, e);
+ }
+ }
+
+ // If the backup is signed, then we need to get the MAC to use to verify it.
+ byte[] signedHash = backupInfo.getSignedHash();
+ Mac mac = null;
+ if (signedHash != null)
+ {
+ String macKeyID =
+ backupInfo.getBackupProperty(BACKUP_PROPERTY_MAC_KEY_ID);
+ if (macKeyID == null)
+ {
+ Message message = ERR_TASKS_RESTORE_UNKNOWN_MAC.get(backupID);
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message);
+ }
+
+ try
+ {
+ mac = DirectoryServer.getCryptoManager().getMacEngine(macKeyID);
+ }
+ catch (Exception e)
+ {
+ Message message = ERR_TASKS_RESTORE_CANNOT_GET_MAC.get(
+ backupID, macKeyID);
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message, e);
+ }
+ }
+
+ // Create the input stream that will be used to read the backup file. At
+ // its core, it will be a file input stream.
+ InputStream inputStream;
+ try
+ {
+ inputStream = new FileInputStream(backupFile);
+ }
+ catch (Exception e)
+ {
+ Message message = ERR_TASKS_RESTORE_CANNOT_OPEN_BACKUP_FILE.get(
+ backupID, backupFile.getPath(), stackTraceToSingleLineString(e));
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message, e);
+ }
+
+ // If the backup is encrypted, then we need to wrap the file input stream
+ // in a cipher input stream.
+ if (backupInfo.isEncrypted())
+ {
+ try
+ {
+ inputStream = DirectoryServer.getCryptoManager()
+ .getCipherInputStream(inputStream);
+ }
+ catch (CryptoManagerException e)
+ {
+ Message message = ERR_TASKS_RESTORE_CANNOT_GET_CIPHER.get(
+ backupFile.getPath(), stackTraceToSingleLineString(e));
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message, e);
+ }
+ }
+
+ // Now wrap the resulting input stream in a zip stream so that we can read
+ // its contents. We don't need to worry about whether to use compression or
+ // not because it will be handled automatically.
+ ZipInputStream zipStream = new ZipInputStream(inputStream);
+
+ // Read through the archive file an entry at a time. For each entry, update
+ // the digest or MAC if necessary.
+ byte[] buffer = new byte[8192];
+ while (true)
+ {
+ ZipEntry zipEntry;
+ try
+ {
+ zipEntry = zipStream.getNextEntry();
+ }
+ catch (Exception e)
+ {
+ Message message = ERR_TASKS_RESTORE_CANNOT_GET_ZIP_ENTRY.get(
+ backupID, backupFile.getPath(), stackTraceToSingleLineString(e));
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message, e);
+ }
+
+ if (zipEntry == null)
+ {
+ break;
+ }
+
+ // Get the filename for the zip entry and update the digest or MAC as
+ // necessary.
+ String fileName = zipEntry.getName();
+ if (digest != null)
+ {
+ digest.update(getBytes(fileName));
+ }
+ if (mac != null)
+ {
+ mac.update(getBytes(fileName));
+ }
+
+ // If we're doing the restore, then create the output stream to write the
+ // file.
+ File tasksFile = getFileForPath(taskBackingFile);
+ String baseDirPath = tasksFile.getParent();
+ OutputStream outputStream = null;
+
+ if (!verifyOnly)
+ {
+ String filePath = baseDirPath + File.separator + fileName;
+ try
+ {
+ outputStream = new FileOutputStream(filePath);
+ }
+ catch (Exception e)
+ {
+ Message message = ERR_TASKS_RESTORE_CANNOT_CREATE_FILE.get(
+ backupID, filePath, stackTraceToSingleLineString(e));
+ throw new DirectoryException(
+ DirectoryServer.getServerErrorResultCode(), message,
+ e);
+ }
+ }
+
+ // Read the contents of the file and update the digest or MAC as
+ // necessary.
+ try
+ {
+ while (true)
+ {
+ int bytesRead = zipStream.read(buffer);
+ if (bytesRead < 0)
+ {
+ // We've reached the end of the entry.
+ break;
+ }
+
+ // Update the digest or MAC if appropriate.
+ if (digest != null)
+ {
+ digest.update(buffer, 0, bytesRead);
+ }
+
+ if (mac != null)
+ {
+ mac.update(buffer, 0, bytesRead);
+ }
+
+ // Write the data to the output stream if appropriate.
+ if (outputStream != null)
+ {
+ outputStream.write(buffer, 0, bytesRead);
+ }
+ }
+
+ // We're at the end of the file so close the output stream if we're
+ // writing it.
+ if (outputStream != null)
+ {
+ outputStream.close();
+ }
+ }
+ catch (Exception e)
+ {
+ Message message = ERR_TASKS_RESTORE_CANNOT_PROCESS_ARCHIVE_FILE.get(
+ backupID, fileName, stackTraceToSingleLineString(e));
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message, e);
+ }
+ }
+
+ // Close the zip stream since we don't need it anymore.
+ try
+ {
+ zipStream.close();
+ }
+ catch (Exception e)
+ {
+ Message message = ERR_TASKS_RESTORE_ERROR_ON_ZIP_STREAM_CLOSE.get(
+ backupID, backupFile.getPath(), stackTraceToSingleLineString(e));
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message, e);
+ }
+
+ // At this point, we should be done with the contents of the ZIP file and
+ // the restore should be complete. If we were generating a digest or MAC,
+ // then make sure it checks out.
+ if (digest != null)
+ {
+ byte[] calculatedHash = digest.digest();
+ if (Arrays.equals(calculatedHash, unsignedHash))
+ {
+ Message message = NOTE_TASKS_RESTORE_UNSIGNED_HASH_VALID.get();
+ logError(message);
+ }
+ else
+ {
+ Message message =
+ ERR_TASKS_RESTORE_UNSIGNED_HASH_INVALID.get(backupID);
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message);
+ }
+ }
+
+ if (mac != null)
+ {
+ byte[] calculatedSignature = mac.doFinal();
+ if (Arrays.equals(calculatedSignature, signedHash))
+ {
+ Message message = NOTE_TASKS_RESTORE_SIGNED_HASH_VALID.get();
+ logError(message);
+ }
+ else
+ {
+ Message message = ERR_TASKS_RESTORE_SIGNED_HASH_INVALID.get(backupID);
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message);
+ }
+ }
+
+ // If we are just verifying the archive, then we're done.
+ if (verifyOnly)
+ {
+ Message message =
+ NOTE_TASKS_RESTORE_VERIFY_SUCCESSFUL.get(backupID, backupPath);
+ logError(message);
+ return;
+ }
+
+ // If we've gotten here, then the archive was restored successfully.
+ Message message = NOTE_TASKS_RESTORE_SUCCESSFUL.get(backupID, backupPath);
+ logError(message);
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/LDIFExportConfig.java b/opendj-sdk/opends/src/server/org/opends/server/types/LDIFExportConfig.java
index 82f179c..6e74dba 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/types/LDIFExportConfig.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/types/LDIFExportConfig.java
@@ -909,18 +909,18 @@
// FIXME -- Need to add code to generate a signed hash of the LDIF
// content.
- try
- {
- writer.close();
- }
- catch (Exception e)
- {
- if (debugEnabled())
+ if (writer != null) {
+ try
{
- TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ writer.close();
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
}
}
}
}
-
-
diff --git a/opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java b/opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java
index 6403536..d18352c 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java
@@ -2352,6 +2352,14 @@
/**
+ * The base filename to use for the archive file containing a backup of the
+ * task backend.
+ */
+ public static final String TASKS_BACKUP_BASE_FILENAME = "tasks-backup-";
+
+
+
+ /**
* The name of the directory in which lock files will be placed.
*/
public static final String LOCKS_DIRECTORY = "locks";
--
Gitblit v1.10.0