1 /* 2 * Copyright (C) 2012 Google Inc. and others 3 * 4 * This program and the accompanying materials are made available under the 5 * terms of the Eclipse Distribution License v. 1.0 which is available at 6 * https://www.eclipse.org/org/documents/edl-v10.php. 7 * 8 * SPDX-License-Identifier: BSD-3-Clause 9 */ 10 package org.eclipse.jgit.archive; 11 12 import static java.nio.charset.StandardCharsets.UTF_8; 13 14 import java.io.IOException; 15 import java.io.OutputStream; 16 import java.text.MessageFormat; 17 import java.util.Arrays; 18 import java.util.Collections; 19 import java.util.List; 20 import java.util.Map; 21 22 import org.apache.commons.compress.archivers.ArchiveOutputStream; 23 import org.apache.commons.compress.archivers.tar.TarArchiveEntry; 24 import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; 25 import org.apache.commons.compress.archivers.tar.TarConstants; 26 import org.eclipse.jgit.api.ArchiveCommand; 27 import org.eclipse.jgit.archive.internal.ArchiveText; 28 import org.eclipse.jgit.lib.FileMode; 29 import org.eclipse.jgit.lib.ObjectId; 30 import org.eclipse.jgit.lib.ObjectLoader; 31 import org.eclipse.jgit.revwalk.RevCommit; 32 33 34 /** 35 * Unix TAR format (ustar + some PAX extensions). 36 */ 37 public final class TarFormat extends BaseFormat implements 38 ArchiveCommand.Format<ArchiveOutputStream> { 39 private static final List<String> SUFFIXES = Collections 40 .unmodifiableList(Arrays.asList(".tar")); //$NON-NLS-1$ 41 42 /** {@inheritDoc} */ 43 @Override createArchiveOutputStream(OutputStream s)44 public ArchiveOutputStream createArchiveOutputStream(OutputStream s) 45 throws IOException { 46 return createArchiveOutputStream(s, 47 Collections.<String, Object> emptyMap()); 48 } 49 50 /** {@inheritDoc} */ 51 @Override createArchiveOutputStream(OutputStream s, Map<String, Object> o)52 public ArchiveOutputStream createArchiveOutputStream(OutputStream s, 53 Map<String, Object> o) throws IOException { 54 TarArchiveOutputStream out = new TarArchiveOutputStream(s, 55 UTF_8.name()); 56 out.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX); 57 out.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX); 58 return applyFormatOptions(out, o); 59 } 60 61 /** {@inheritDoc} */ 62 @Override putEntry(ArchiveOutputStream out, ObjectId tree, String path, FileMode mode, ObjectLoader loader)63 public void putEntry(ArchiveOutputStream out, 64 ObjectId tree, String path, FileMode mode, ObjectLoader loader) 65 throws IOException { 66 if (mode == FileMode.SYMLINK) { 67 final TarArchiveEntry entry = new TarArchiveEntry( 68 path, TarConstants.LF_SYMLINK); 69 entry.setLinkName(new String(loader.getCachedBytes(100), UTF_8)); 70 out.putArchiveEntry(entry); 71 out.closeArchiveEntry(); 72 return; 73 } 74 75 // TarArchiveEntry detects directories by checking 76 // for '/' at the end of the filename. 77 if (path.endsWith("/") && mode != FileMode.TREE) //$NON-NLS-1$ 78 throw new IllegalArgumentException(MessageFormat.format( 79 ArchiveText.get().pathDoesNotMatchMode, path, mode)); 80 if (!path.endsWith("/") && mode == FileMode.TREE) //$NON-NLS-1$ 81 path = path + "/"; //$NON-NLS-1$ 82 83 final TarArchiveEntry entry = new TarArchiveEntry(path); 84 85 if (tree instanceof RevCommit) { 86 long t = ((RevCommit) tree).getCommitTime() * 1000L; 87 entry.setModTime(t); 88 } 89 90 if (mode == FileMode.TREE) { 91 out.putArchiveEntry(entry); 92 out.closeArchiveEntry(); 93 return; 94 } 95 96 if (mode == FileMode.REGULAR_FILE) { 97 // ok 98 } else if (mode == FileMode.EXECUTABLE_FILE) { 99 entry.setMode(mode.getBits()); 100 } else { 101 // Unsupported mode (e.g., GITLINK). 102 throw new IllegalArgumentException(MessageFormat.format( 103 ArchiveText.get().unsupportedMode, mode)); 104 } 105 entry.setSize(loader.getSize()); 106 out.putArchiveEntry(entry); 107 loader.copyTo(out); 108 out.closeArchiveEntry(); 109 } 110 111 /** {@inheritDoc} */ 112 @Override suffixes()113 public Iterable<String> suffixes() { 114 return SUFFIXES; 115 } 116 117 /** {@inheritDoc} */ 118 @Override equals(Object other)119 public boolean equals(Object other) { 120 return (other instanceof TarFormat); 121 } 122 123 /** {@inheritDoc} */ 124 @Override hashCode()125 public int hashCode() { 126 return getClass().hashCode(); 127 } 128 } 129