org.neo4j.dbms.archive.Dumper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of neo4j-dbms Show documentation
Show all versions of neo4j-dbms Show documentation
This component provides management functionality and product surface for Neo4j instances.
/*
* Copyright (c) 2002-2018 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.neo4j.dbms.archive;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.function.Predicate;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveOutputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import org.neo4j.function.ThrowingAction;
import static org.neo4j.dbms.archive.Utils.checkWritableDirectory;
import static org.neo4j.dbms.archive.Utils.copy;
import static org.neo4j.function.Predicates.not;
import static org.neo4j.function.ThrowingAction.noop;
import static org.neo4j.io.fs.FileVisitors.justContinue;
import static org.neo4j.io.fs.FileVisitors.onDirectory;
import static org.neo4j.io.fs.FileVisitors.onFile;
import static org.neo4j.io.fs.FileVisitors.onlyMatching;
import static org.neo4j.io.fs.FileVisitors.throwExceptions;
public class Dumper
{
public void dump( Path root, Path archive, Predicate exclude ) throws IOException
{
checkWritableDirectory( archive.getParent() );
try ( ArchiveOutputStream stream = openArchiveOut( archive ) )
{
Files.walkFileTree( root,
onlyMatching( not( exclude ),
throwExceptions(
onDirectory( dir -> dumpDirectory( root, stream, dir ),
onFile( file -> dumpFile( root, stream, file ),
justContinue() ) ) ) ) );
}
}
private static ArchiveOutputStream openArchiveOut( Path archive ) throws IOException
{
// StandardOpenOption.CREATE_NEW is important here because it atomically asserts that the file doesn't
// exist as it is opened, avoiding a TOCTOU race condition which results in a security vulnerability. I
// can't see a way to write a test to verify that we are using this option rather than just implementing
// the check ourselves non-atomically.
TarArchiveOutputStream tarball =
new TarArchiveOutputStream( new GzipCompressorOutputStream(
Files.newOutputStream( archive, StandardOpenOption.CREATE_NEW ) ) );
tarball.setLongFileMode( TarArchiveOutputStream.LONGFILE_POSIX );
tarball.setBigNumberMode( TarArchiveOutputStream.BIGNUMBER_POSIX );
return tarball;
}
private void dumpFile( Path root, ArchiveOutputStream stream, Path file ) throws IOException
{
withEntry( () -> writeFile( file, stream ), root, stream, file );
}
private void dumpDirectory( Path root, ArchiveOutputStream stream, Path dir ) throws IOException
{
withEntry( noop(), root, stream, dir );
}
private void withEntry( ThrowingAction operation, Path root, ArchiveOutputStream stream, Path file )
throws IOException
{
ArchiveEntry entry = createEntry( file, root, stream );
stream.putArchiveEntry( entry );
operation.apply();
stream.closeArchiveEntry();
}
private ArchiveEntry createEntry( Path file, Path root, ArchiveOutputStream archive ) throws IOException
{
return archive.createArchiveEntry( file.toFile(), "./" + root.relativize( file ).toString() );
}
private void writeFile( Path file, ArchiveOutputStream archiveStream ) throws IOException
{
try ( InputStream in = Files.newInputStream( file ) )
{
copy( in, archiveStream );
}
}
}