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.