Bugfix for long filenames in tar (#1552)

Fixes errors with long file names in tar archives. This may arise with hg repositories with deep directories.
This commit is contained in:
René Pfeuffer
2021-02-18 16:30:35 +01:00
committed by GitHub
parent d8427ed4ed
commit d0df8977ef
14 changed files with 316 additions and 135 deletions

View File

@@ -98,6 +98,9 @@ dependencies {
annotationProcessor libraries.sspProcessor
testImplementation libraries.shiroUnit
// compression
implementation libraries.commonsCompress
// tests
testImplementation libraries.junitJupiterApi
testImplementation libraries.junitJupiterParams

View File

@@ -0,0 +1,218 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm.util;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.function.Predicate;
import java.util.stream.Stream;
public final class Archives {
private Archives() {
}
/**
* Creates a tar output stream that is backed by the given output stream.
* @param dest The stream the tar should be written to.
*/
public static TarArchiveOutputStream createTarOutputStream(OutputStream dest) {
BufferedOutputStream bos = new BufferedOutputStream(dest);
TarArchiveOutputStream tarArchiveOutputStream = new TarArchiveOutputStream(bos);
tarArchiveOutputStream.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
tarArchiveOutputStream.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX);
return tarArchiveOutputStream;
}
/**
* Creates a tar input stream that takes its bytes from the given input stream.
* @param source The stream the tar should be extracted from.
*/
public static TarArchiveInputStream createTarInputStream(InputStream source) {
return new TarArchiveInputStream(source);
}
/**
* Prepare bundling a complete {@link Path} in a tar. Aside from the path whose files shall be added to the tar,
* it is possible to specify a base path for the tar archive ({@link TarWriter#withBasePath(String)}) and to
* specify a filter to select what files shall be added ({@link TarWriter#withFilter(Predicate)}). To start
* the process, {@link TarWriter#run()} has to be called.
* <br>
* Example:
* <pre>
* Archives.addPathToTar(Paths.get("some/dir"), Files.newOutputStream("my.tar"))
* .filter(path -> !path.toString().endsWith("~"))
* .run();
* </pre>
* @param path The path containing the files to be added to the tar.
* @param outputStream The output stream the tar shall be written to.
* @return Instance of {@link TarWriter}.
*/
public static TarWriter addPathToTar(Path path, OutputStream outputStream) {
return new TarWriter(path, outputStream);
}
/**
* Extracts files from a input stream with a tar.
* <br>
* Example:
* <pre>
* Archives.extractTar(Files.newOutputStream("my.tar"), Paths.get("target/dir"))
* .run();
* </pre>
* @param inputStream The input stream providing the tar stream.
* @param targetPath The target path to write the files to.
* @return Instance of {@link TarExtractor}.
*/
public static TarExtractor extractTar(InputStream inputStream, Path targetPath) {
return new TarExtractor(inputStream, targetPath);
}
/**
* Class used in {@link #addPathToTar(Path, OutputStream)}.
*/
public static class TarWriter {
private final Path path;
private final OutputStream outputStream;
private String basePath = "";
private Predicate<Path> filter = path -> true;
TarWriter(Path path, OutputStream outputStream) {
this.path = path;
this.outputStream = outputStream;
}
/**
* Sets a base path that will be prepended to every tar entry in the archive.
*/
public TarWriter withBasePath(String basePath) {
this.basePath = basePath;
return this;
}
/**
* Sets a filter to select which files shall be added to the archive.
*/
public TarWriter withFilter(Predicate<Path> filter) {
this.filter = filter;
return this;
}
/**
* Starts the process.
*/
public void run() throws IOException {
try (TarArchiveOutputStream tarArchiveOutputStream = Archives.createTarOutputStream(outputStream)) {
createTarEntryForFiles(basePath, path, tarArchiveOutputStream);
tarArchiveOutputStream.finish();
}
}
private void createTarEntryForFiles(String path, Path fileOrDir, TarArchiveOutputStream taos) throws IOException {
try (Stream<Path> files = Files.list(fileOrDir)) {
if (files != null) {
files
.filter(filter)
.forEach(f -> bundleFileOrDir(path, f, taos));
}
}
}
@SuppressWarnings("java:S1075") // We use / here because we build tar entries, not files
private void bundleFileOrDir(String path, Path fileOrDir, TarArchiveOutputStream taos) {
try {
String filePath = path + "/" + fileOrDir.getFileName().toString();
if (Files.isDirectory(fileOrDir)) {
createTarEntryForFiles(filePath, fileOrDir, taos);
} else {
createArchiveEntryForFile(filePath, fileOrDir, taos);
}
} catch (IOException e) {
throw new ArchiveException(
"Could not add file '" + fileOrDir + "' to tar archive as '" + path + "'",
e
);
}
}
private void createArchiveEntryForFile(String filePath, Path path, TarArchiveOutputStream taos) throws IOException {
TarArchiveEntry entry = new TarArchiveEntry(filePath);
entry.setSize(path.toFile().length());
taos.putArchiveEntry(entry);
Files.copy(path, taos);
taos.closeArchiveEntry();
}
}
/**
* Classed used in {@link #extractTar(InputStream, Path)}.
*/
public static class TarExtractor {
private final InputStream inputStream;
private final Path targetPath;
TarExtractor(InputStream inputStream, Path targetPath) {
this.inputStream = inputStream;
this.targetPath = targetPath;
}
/**
* Starts the process.
*/
public void run() throws IOException {
try (TarArchiveInputStream tais = createTarInputStream(inputStream)) {
TarArchiveEntry entry;
while ((entry = tais.getNextTarEntry()) != null) {
Path filePath = targetPath.resolve(entry.getName());
createDirectoriesIfNestedFile(filePath);
Files.copy(tais, filePath, StandardCopyOption.REPLACE_EXISTING);
}
}
}
private void createDirectoriesIfNestedFile(Path filePath) throws IOException {
Path directory = filePath.getParent();
if (!Files.exists(directory)) {
Files.createDirectories(directory);
}
}
}
public static final class ArchiveException extends RuntimeException {
public ArchiveException(String message, Throwable cause) {
super(message, cause);
}
}
}

View File

@@ -0,0 +1,67 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm.util;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import static java.util.Collections.singleton;
import static org.assertj.core.api.Assertions.assertThat;
import static sonia.scm.util.Archives.addPathToTar;
import static sonia.scm.util.Archives.extractTar;
import static sonia.scm.util.Archives.createTarOutputStream;
class ArchivesTest {
@Test
void writeAndReadTar(@TempDir Path temp) throws IOException {
Path source = temp.resolve("source");
Files.createDirectories(source);
Path file = source.resolve("file");
Path fileInDirectory = source.resolve("some").resolve("very").resolve("deep").resolve("nested").resolve("directory").resolve("with").resolve("file");
Files.createDirectories(fileInDirectory.getParent());
Files.write(file, singleton("content"));
Files.write(fileInDirectory, singleton("content in directory"));
Path tarFile = temp.resolve("test.tar");
try (OutputStream outputStream = Files.newOutputStream(tarFile)) {
addPathToTar(source, outputStream).run();
}
Path target = temp.resolve("target");
Files.createDirectories(target);
extractTar(Files.newInputStream(tarFile), target).run();
assertThat(target.resolve("file")).hasContent("content");
assertThat(target.resolve("some").resolve("very").resolve("deep").resolve("nested").resolve("directory").resolve("with").resolve("file")).hasContent("content in directory");
}
}

View File

@@ -23,18 +23,16 @@
*/
package sonia.scm.repository.spi;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import sonia.scm.ContextEntry;
import sonia.scm.repository.api.BundleResponse;
import sonia.scm.repository.api.ExportFailedException;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
import static sonia.scm.util.Archives.addPathToTar;
public class GitBundleCommand extends AbstractGitCommand implements BundleCommand {
@@ -48,12 +46,8 @@ public class GitBundleCommand extends AbstractGitCommand implements BundleComman
public BundleResponse bundle(BundleCommandRequest request) throws IOException {
Path repoDir = context.getDirectory().toPath();
if (Files.exists(repoDir)) {
try (OutputStream os = request.getArchive().openStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
TarArchiveOutputStream taos = new TarArchiveOutputStream(bos)) {
createTarEntryForFiles("", repoDir, taos);
taos.finish();
try (OutputStream os = request.getArchive().openStream()) {
addPathToTar(repoDir, os).withFilter(this::shouldIncludeFile).run();
}
} else {
throw new ExportFailedException(
@@ -69,42 +63,7 @@ public class GitBundleCommand extends AbstractGitCommand implements BundleComman
return TAR_ARCHIVE;
}
private void createTarEntryForFiles(String path, Path fileOrDir, TarArchiveOutputStream taos) throws IOException {
try (Stream<Path> files = Files.list(fileOrDir)) {
if (files != null) {
files
.filter(this::shouldIncludeFile)
.forEach(f -> bundleFileOrDir(path, f, taos));
}
}
}
private void bundleFileOrDir(String path, Path fileOrDir, TarArchiveOutputStream taos) {
try {
String filePath = path + "/" + fileOrDir.getFileName().toString();
if (Files.isDirectory(fileOrDir)) {
createTarEntryForFiles(filePath, fileOrDir, taos);
} else {
createArchiveEntryForFile(filePath, fileOrDir, taos);
}
} catch (IOException e) {
throw new ExportFailedException(
ContextEntry.ContextBuilder.noContext(),
"Could not export repository. Error on bundling files.",
e
);
}
}
private boolean shouldIncludeFile(Path filePath) {
return !filePath.getFileName().toString().equals("config");
}
private void createArchiveEntryForFile(String filePath, Path path, TarArchiveOutputStream taos) throws IOException {
TarArchiveEntry entry = new TarArchiveEntry(filePath);
entry.setSize(path.toFile().length());
taos.putArchiveEntry(entry);
Files.copy(path, taos);
taos.closeArchiveEntry();
}
}

View File

@@ -24,8 +24,6 @@
package sonia.scm.repository.spi;
import com.google.common.io.ByteSource;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.repository.api.UnbundleResponse;
@@ -33,10 +31,9 @@ import sonia.scm.repository.api.UnbundleResponse;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import static com.google.common.base.Preconditions.checkNotNull;
import static sonia.scm.util.Archives.extractTar;
public class GitUnbundleCommand extends AbstractGitCommand implements UnbundleCommand {
@@ -61,20 +58,6 @@ public class GitUnbundleCommand extends AbstractGitCommand implements UnbundleCo
}
private void unbundleRepositoryFromRequest(UnbundleCommandRequest request, Path repositoryDir) throws IOException {
try (TarArchiveInputStream tais = new TarArchiveInputStream(request.getArchive().openBufferedStream())) {
TarArchiveEntry entry;
while ((entry = tais.getNextTarEntry()) != null) {
Path filePath = repositoryDir.resolve(entry.getName());
createDirectoriesIfNestedFile(filePath);
Files.copy(tais, filePath, StandardCopyOption.REPLACE_EXISTING);
}
}
}
private void createDirectoriesIfNestedFile(Path filePath) throws IOException {
Path directory = filePath.getParent();
if (!Files.exists(directory)) {
Files.createDirectories(directory);
}
extractTar(request.getArchive().openBufferedStream(), repositoryDir).run();
}
}

View File

@@ -42,6 +42,7 @@ import java.nio.file.StandardCopyOption;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static sonia.scm.util.Archives.createTarInputStream;
class GitBundleCommandTest {
@@ -94,7 +95,7 @@ class GitBundleCommandTest {
}
private void assertStreamContainsContent(ByteArrayOutputStream baos, String content) throws IOException {
TarArchiveInputStream tais = new TarArchiveInputStream(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())));
TarArchiveInputStream tais = createTarInputStream(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())));
tais.getNextEntry();
byte[] result = IOUtils.toByteArray(tais);

View File

@@ -30,8 +30,8 @@ import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import sonia.scm.util.Archives;
import javax.annotation.Nonnull;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
@@ -82,9 +82,10 @@ class GitUnbundleCommandTest extends AbstractGitCommandTestBase {
private UnbundleCommandRequest createUnbundleCommandRequestForFile(Path temp, String filePath, String fileContent) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
TarArchiveOutputStream taos = new TarArchiveOutputStream(baos);
TarArchiveOutputStream taos = Archives.createTarOutputStream(baos);
addEntry(taos, filePath, fileContent);
taos.finish();
taos.close();
when(gitContext.getDirectory()).thenReturn(temp.toFile());
ByteSource byteSource = ByteSource.wrap(baos.toByteArray());

View File

@@ -24,18 +24,16 @@
package sonia.scm.repository.spi;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import sonia.scm.ContextEntry;
import sonia.scm.repository.api.BundleResponse;
import sonia.scm.repository.api.ExportFailedException;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
import static sonia.scm.util.Archives.addPathToTar;
public class HgBundleCommand implements BundleCommand {
@@ -51,12 +49,8 @@ public class HgBundleCommand implements BundleCommand {
public BundleResponse bundle(BundleCommandRequest request) throws IOException {
Path repoDir = context.getDirectory().toPath();
if (Files.exists(repoDir)) {
try (OutputStream os = request.getArchive().openStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
TarArchiveOutputStream taos = new TarArchiveOutputStream(bos)) {
createTarEntryForFiles("", repoDir, taos);
taos.finish();
try (OutputStream os = request.getArchive().openStream()) {
addPathToTar(repoDir, os).run();
}
} else {
throw new ExportFailedException(
@@ -71,37 +65,4 @@ public class HgBundleCommand implements BundleCommand {
public String getFileExtension() {
return TAR_ARCHIVE;
}
private void createTarEntryForFiles(String path, Path fileOrDir, TarArchiveOutputStream taos) throws IOException {
try (Stream<Path> files = Files.list(fileOrDir)) {
if (files != null) {
files.forEach(f -> bundleFileOrDir(path, f, taos));
}
}
}
private void bundleFileOrDir(String path, Path fileOrDir, TarArchiveOutputStream taos) {
try {
String filePath = path + "/" + fileOrDir.getFileName().toString();
if (Files.isDirectory(fileOrDir)) {
createTarEntryForFiles(filePath, fileOrDir, taos);
} else {
createArchiveEntryForFile(filePath, fileOrDir, taos);
}
} catch (IOException e) {
throw new ExportFailedException(
ContextEntry.ContextBuilder.noContext(),
"Could not export repository. Error on bundling files.",
e
);
}
}
private void createArchiveEntryForFile(String filePath, Path path, TarArchiveOutputStream taos) throws IOException {
TarArchiveEntry entry = new TarArchiveEntry(filePath);
entry.setSize(path.toFile().length());
taos.putArchiveEntry(entry);
Files.copy(path, taos);
taos.closeArchiveEntry();
}
}

View File

@@ -25,8 +25,6 @@
package sonia.scm.repository.spi;
import com.google.common.io.ByteSource;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.repository.api.UnbundleResponse;
@@ -34,9 +32,9 @@ import sonia.scm.repository.api.UnbundleResponse;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import static com.google.common.base.Preconditions.checkNotNull;
import static sonia.scm.util.Archives.extractTar;
public class HgUnbundleCommand implements UnbundleCommand {
@@ -63,20 +61,6 @@ public class HgUnbundleCommand implements UnbundleCommand {
}
private void unbundleRepositoryFromRequest(UnbundleCommandRequest request, Path repositoryDir) throws IOException {
try (TarArchiveInputStream tais = new TarArchiveInputStream(request.getArchive().openBufferedStream())) {
TarArchiveEntry entry;
while ((entry = tais.getNextTarEntry()) != null) {
Path filePath = repositoryDir.resolve(entry.getName());
createDirectoriesIfNestedFile(filePath);
Files.copy(tais, filePath, StandardCopyOption.REPLACE_EXISTING);
}
}
}
private void createDirectoriesIfNestedFile(Path filePath) throws IOException {
Path directory = filePath.getParent();
if (!Files.exists(directory)) {
Files.createDirectories(directory);
}
extractTar(request.getArchive().openBufferedStream(), repositoryDir).run();
}
}

View File

@@ -43,6 +43,7 @@ import java.nio.file.StandardCopyOption;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static sonia.scm.util.Archives.createTarInputStream;
class HgBundleCommandTest {
@@ -95,7 +96,7 @@ class HgBundleCommandTest {
}
private void assertStreamContainsContent(ByteArrayOutputStream baos, String content) throws IOException {
TarArchiveInputStream tais = new TarArchiveInputStream(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())));
TarArchiveInputStream tais = createTarInputStream(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())));
tais.getNextEntry();
byte[] result = IOUtils.toByteArray(tais);

View File

@@ -31,6 +31,7 @@ import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import sonia.scm.util.Archives;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -82,9 +83,10 @@ class HgUnbundleCommandTest {
private UnbundleCommandRequest createUnbundleCommandRequestForFile(Path temp, String filePath, String fileContent) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
TarArchiveOutputStream taos = new TarArchiveOutputStream(baos);
TarArchiveOutputStream taos = Archives.createTarOutputStream(baos);
addEntry(taos, filePath, fileContent);
taos.finish();
taos.close();
when(hgContext.getDirectory()).thenReturn(temp.toFile());
ByteSource byteSource = ByteSource.wrap(baos.toByteArray());

View File

@@ -34,6 +34,7 @@ import sonia.scm.repository.api.ExportFailedException;
import sonia.scm.repository.api.RepositoryService;
import sonia.scm.repository.api.RepositoryServiceFactory;
import sonia.scm.repository.work.WorkdirProvider;
import sonia.scm.util.Archives;
import sonia.scm.util.IOUtil;
import javax.inject.Inject;
@@ -84,7 +85,7 @@ public class FullScmRepositoryExporter {
RepositoryService service = serviceFactory.create(repository);
BufferedOutputStream bos = new BufferedOutputStream(outputStream);
GzipCompressorOutputStream gzos = new GzipCompressorOutputStream(bos);
TarArchiveOutputStream taos = new TarArchiveOutputStream(gzos)
TarArchiveOutputStream taos = Archives.createTarOutputStream(gzos)
) {
writeEnvironmentData(taos);
writeMetadata(repository, taos);

View File

@@ -40,6 +40,7 @@ import java.io.IOException;
import java.io.InputStream;
import static java.util.Arrays.stream;
import static sonia.scm.util.Archives.createTarInputStream;
public class FullScmRepositoryImporter {
@@ -65,7 +66,7 @@ public class FullScmRepositoryImporter {
try (
BufferedInputStream bif = new BufferedInputStream(inputStream);
GzipCompressorInputStream gcis = new GzipCompressorInputStream(bif);
TarArchiveInputStream tais = new TarArchiveInputStream(gcis)
TarArchiveInputStream tais = createTarInputStream(gcis)
) {
return run(repository, tais);
}

View File

@@ -35,9 +35,9 @@ import sonia.scm.store.ExportableStore;
import sonia.scm.store.StoreEntryMetaData;
import sonia.scm.store.StoreExporter;
import sonia.scm.store.StoreType;
import sonia.scm.util.Archives;
import javax.inject.Inject;
import java.io.BufferedOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -58,8 +58,7 @@ public class TarArchiveRepositoryStoreExporter {
public void export(Repository repository, OutputStream output) {
try (
BufferedOutputStream bos = new BufferedOutputStream(output);
final TarArchiveOutputStream taos = new TarArchiveOutputStream(bos)
final TarArchiveOutputStream taos = Archives.createTarOutputStream(output)
) {
List<ExportableStore> exportableStores = storeExporter.listExportableStores(repository);
for (ExportableStore store : exportableStores) {