org.h2.tools.Restore Maven / Gradle / Ivy
/*
* Copyright 2004-2019 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (https://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.tools;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.SQLException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.h2.engine.Constants;
import org.h2.engine.SysProperties;
import org.h2.message.DbException;
import org.h2.store.fs.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.Tool;
/**
* Restores a H2 database by extracting the database files from a .zip file.
* @h2.resource
*/
public class Restore extends Tool {
/**
* Options are case sensitive. Supported options are:
*
* [-help] or [-?]
* Print the list of options
* [-file <filename>]
* The source file name (default: backup.zip)
* [-dir <dir>]
* The target directory (default: .)
* [-db <database>]
* The target database name (as stored if not set)
* [-quiet]
* Do not print progress information
*
* @h2.resource
*
* @param args the command line arguments
*/
public static void main(String... args) throws SQLException {
new Restore().runTool(args);
}
@Override
public void runTool(String... args) throws SQLException {
String zipFileName = "backup.zip";
String dir = ".";
String db = null;
for (int i = 0; args != null && i < args.length; i++) {
String arg = args[i];
if (arg.equals("-dir")) {
dir = args[++i];
} else if (arg.equals("-file")) {
zipFileName = args[++i];
} else if (arg.equals("-db")) {
db = args[++i];
} else if (arg.equals("-quiet")) {
// ignore
} else if (arg.equals("-help") || arg.equals("-?")) {
showUsage();
return;
} else {
showUsageAndThrowUnsupportedOption(arg);
}
}
execute(zipFileName, dir, db);
}
private static String getOriginalDbName(String fileName, String db)
throws IOException {
try (InputStream in = FileUtils.newInputStream(fileName)) {
ZipInputStream zipIn = new ZipInputStream(in);
String originalDbName = null;
boolean multiple = false;
while (true) {
ZipEntry entry = zipIn.getNextEntry();
if (entry == null) {
break;
}
String entryName = entry.getName();
zipIn.closeEntry();
String name = getDatabaseNameFromFileName(entryName);
if (name != null) {
if (db.equals(name)) {
originalDbName = name;
// we found the correct database
break;
} else if (originalDbName == null) {
originalDbName = name;
// we found a database, but maybe another one
} else {
// we have found multiple databases, but not the correct
// one
multiple = true;
}
}
}
zipIn.close();
if (multiple && !db.equals(originalDbName)) {
throw new IOException("Multiple databases found, but not " + db);
}
return originalDbName;
}
}
/**
* Extract the name of the database from a given file name.
* Only files ending with .h2.db are considered, all others return null.
*
* @param fileName the file name (without directory)
* @return the database name or null
*/
private static String getDatabaseNameFromFileName(String fileName) {
if (fileName.endsWith(Constants.SUFFIX_PAGE_FILE)) {
return fileName.substring(0,
fileName.length() - Constants.SUFFIX_PAGE_FILE.length());
}
if (fileName.endsWith(Constants.SUFFIX_MV_FILE)) {
return fileName.substring(0,
fileName.length() - Constants.SUFFIX_MV_FILE.length());
}
return null;
}
/**
* Restores database files.
*
* @param zipFileName the name of the backup file
* @param directory the directory name
* @param db the database name (null for all databases)
* @throws DbException if there is an IOException
*/
public static void execute(String zipFileName, String directory, String db) {
InputStream in = null;
try {
if (!FileUtils.exists(zipFileName)) {
throw new IOException("File not found: " + zipFileName);
}
String originalDbName = null;
int originalDbLen = 0;
if (db != null) {
originalDbName = getOriginalDbName(zipFileName, db);
if (originalDbName == null) {
throw new IOException("No database named " + db + " found");
}
if (originalDbName.startsWith(SysProperties.FILE_SEPARATOR)) {
originalDbName = originalDbName.substring(1);
}
originalDbLen = originalDbName.length();
}
in = FileUtils.newInputStream(zipFileName);
try (ZipInputStream zipIn = new ZipInputStream(in)) {
while (true) {
ZipEntry entry = zipIn.getNextEntry();
if (entry == null) {
break;
}
String fileName = entry.getName();
// restoring windows backups on linux and vice versa
fileName = fileName.replace('\\', SysProperties.FILE_SEPARATOR.charAt(0));
fileName = fileName.replace('/', SysProperties.FILE_SEPARATOR.charAt(0));
if (fileName.startsWith(SysProperties.FILE_SEPARATOR)) {
fileName = fileName.substring(1);
}
boolean copy = false;
if (db == null) {
copy = true;
} else if (fileName.startsWith(originalDbName + ".")) {
fileName = db + fileName.substring(originalDbLen);
copy = true;
}
if (copy) {
OutputStream o = null;
try {
o = FileUtils.newOutputStream(
directory + SysProperties.FILE_SEPARATOR + fileName, false);
IOUtils.copy(zipIn, o);
o.close();
} finally {
IOUtils.closeSilently(o);
}
}
zipIn.closeEntry();
}
zipIn.closeEntry();
}
} catch (IOException e) {
throw DbException.convertIOException(e, zipFileName);
} finally {
IOUtils.closeSilently(in);
}
}
}