package org.exist.repo;
import org.exist.dom.persistent.DocumentImpl;
import org.exist.security.PermissionDeniedException;
import org.exist.storage.DBBroker;
import org.exist.storage.NativeBroker;
import org.exist.storage.lock.Lock.LockMode;
import org.exist.util.FileUtils;
import org.exist.xmldb.XmldbURI;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/**
* Utility methods for backing up and restoring the expath file system repository.
*/
public class RepoBackup {
public final static String REPO_ARCHIVE = "expathrepo.zip";
public static Path backup(final DBBroker broker) throws IOException {
final Path tempFile = Files.createTempFile("expathrepo", "zip");
try(final ZipOutputStream os = new ZipOutputStream(Files.newOutputStream(tempFile))) {
final Path directory = ExistRepository.getRepositoryDir(broker.getConfiguration());
zipDir(directory.toAbsolutePath(), os, "");
}
return tempFile;
}
public static void restore(final DBBroker broker) throws IOException, PermissionDeniedException {
final XmldbURI docPath = XmldbURI.createInternal(XmldbURI.ROOT_COLLECTION + "/" + REPO_ARCHIVE);
DocumentImpl doc = null;
try {
doc = broker.getXMLResource(docPath, LockMode.READ_LOCK);
if (doc == null)
{return;}
if (doc.getResourceType() != DocumentImpl.BINARY_FILE)
{throw new IOException(docPath + " is not a binary resource");}
final Path file = ((NativeBroker)broker).getCollectionBinaryFileFsPath(doc.getURI());
final Path directory = ExistRepository.getRepositoryDir(broker.getConfiguration());
unzip(file, directory);
} finally {
if (doc != null)
{doc.getUpdateLock().release(LockMode.READ_LOCK);}
}
}
/**
* Zip up a directory path
*
* @param directory
* @param zos
* @param path
* @throws IOException
*/
public static void zipDir(final Path directory, final ZipOutputStream zos, final String path) throws IOException {
// get a listing of the directory content
final List<Path> dirList = FileUtils.list(directory);
// loop through dirList, and zip the files
for (final Path f : dirList) {
if (Files.isDirectory(f)) {
zipDir(f, zos, path + FileUtils.fileName(f) + "/");
continue;
}
final ZipEntry anEntry = new ZipEntry(path + FileUtils.fileName(f));
zos.putNextEntry(anEntry);
Files.copy(f, zos);
}
}
/***
* Extract zipfile to outdir with complete directory structure.
*
* @param zipfile Input .zip file
* @param outdir Output directory
*/
public static void unzip(final Path zipfile, final Path outdir) throws IOException {
try(final ZipInputStream zin = new ZipInputStream(Files.newInputStream(zipfile))) {
ZipEntry entry;
String name, dir;
while ((entry = zin.getNextEntry()) != null)
{
name = entry.getName();
if(entry.isDirectory() ) {
Files.createDirectories(outdir.resolve(name));
continue;
}
dir = dirpart(name);
if(dir != null) {
Files.createDirectories(outdir.resolve(name));
}
//extract file
Files.copy(zin, outdir.resolve(name));
}
}
}
private static String dirpart(final String name) {
final int s = name.lastIndexOf(File.separatorChar);
return s == -1 ? null : name.substring( 0, s );
}
}