mirror of
				https://github.com/scm-manager/scm-manager.git
				synced 2025-11-03 20:15:52 +01:00 
			
		
		
		
	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:
		@@ -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();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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());
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user