xref: /JGit/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TarFormat.java (revision 5c5f7c6b146b24f2bd4afae1902df85ad6e57ea3)
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