View Javadoc
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
44  	public ArchiveOutputStream createArchiveOutputStream(OutputStream s)
45  			throws IOException {
46  		return createArchiveOutputStream(s,
47  				Collections.<String, Object> emptyMap());
48  	}
49  
50  	/** {@inheritDoc} */
51  	@Override
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
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
113 	public Iterable<String> suffixes() {
114 		return SUFFIXES;
115 	}
116 
117 	/** {@inheritDoc} */
118 	@Override
119 	public boolean equals(Object other) {
120 		return (other instanceof TarFormat);
121 	}
122 
123 	/** {@inheritDoc} */
124 	@Override
125 	public int hashCode() {
126 		return getClass().hashCode();
127 	}
128 }