diff --git a/src/etc/testcases/taskdefs/tar.xml b/src/etc/testcases/taskdefs/tar.xml
index b0f99d5b7..08ac2f79a 100644
--- a/src/etc/testcases/taskdefs/tar.xml
+++ b/src/etc/testcases/taskdefs/tar.xml
@@ -203,4 +203,12 @@
+
+
+
+
+
+
+
+
diff --git a/src/etc/testcases/testtarwithsymlinks.tar.gz b/src/etc/testcases/testtarwithsymlinks.tar.gz
new file mode 100644
index 000000000..782a23727
Binary files /dev/null and b/src/etc/testcases/testtarwithsymlinks.tar.gz differ
diff --git a/src/main/org/apache/tools/ant/taskdefs/Tar.java b/src/main/org/apache/tools/ant/taskdefs/Tar.java
index 76446fdc8..1ab537962 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Tar.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Tar.java
@@ -405,12 +405,7 @@ public class Tar extends MatchingTask {
return;
}
- String prefix = tarFileSet.getPrefix(this.getProject());
- // '/' is appended for compatibility with the zip task.
- if (!prefix.isEmpty() && !prefix.endsWith("/")) {
- prefix += "/";
- }
- vPath = prefix + vPath;
+ vPath = getCanonicalPrefix(tarFileSet, this.getProject()) + vPath;
} else {
vPath = fullpath;
}
@@ -464,6 +459,14 @@ public class Tar extends MatchingTask {
te.setUserId(tr.getLongUid());
te.setGroupName(tr.getGroup());
te.setGroupId(tr.getLongGid());
+ String linkName = tr.getLinkName();
+ byte linkFlag = tr.getLinkFlag();
+ if (linkFlag == TarConstants.LF_LINK &&
+ linkName != null && linkName.length() > 0 && !linkName.startsWith("/")) {
+ linkName = getCanonicalPrefix(tarFileSet, this.getProject()) + linkName;
+ }
+ te.setLinkName(linkName);
+ te.setLinkFlag(linkFlag);
}
}
@@ -785,6 +788,15 @@ public class Tar extends MatchingTask {
return tfs;
}
+ private static String getCanonicalPrefix(TarFileSet tarFileSet, Project project) {
+ String prefix = tarFileSet.getPrefix(project);
+ // '/' is appended for compatibility with the zip task.
+ if (prefix.isEmpty() || prefix.endsWith("/")) {
+ return prefix;
+ }
+ return prefix += "/";
+ }
+
/**
* This is a FileSet with the option to specify permissions
* and other attributes.
diff --git a/src/main/org/apache/tools/ant/types/resources/TarResource.java b/src/main/org/apache/tools/ant/types/resources/TarResource.java
index 9e137cc07..96db041dc 100644
--- a/src/main/org/apache/tools/ant/types/resources/TarResource.java
+++ b/src/main/org/apache/tools/ant/types/resources/TarResource.java
@@ -26,6 +26,7 @@ import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.tar.TarConstants;
import org.apache.tools.tar.TarEntry;
import org.apache.tools.tar.TarInputStream;
@@ -39,6 +40,8 @@ public class TarResource extends ArchiveResource {
private String groupName = "";
private long uid;
private long gid;
+ private byte linkFlag = TarConstants.LF_NORMAL;
+ private String linkName = "";
/**
* Default constructor.
@@ -172,6 +175,22 @@ public class TarResource extends ArchiveResource {
return (int) getLongGid();
}
+ /**
+ * @return the link "name" (=path) of this entry; an empty string if this is no link
+ * @since 1.10.10
+ */
+ public String getLinkName() {
+ return linkName;
+ }
+
+ /**
+ * @return the link "flag" (=type) of this entry
+ * @since 1.10.10
+ */
+ public byte getLinkFlag() {
+ return linkFlag;
+ }
+
/**
* fetches information from the named entry inside the archive.
*/
@@ -213,6 +232,8 @@ public class TarResource extends ArchiveResource {
groupName = e.getGroupName();
uid = e.getLongUserId();
gid = e.getLongGroupId();
+ linkName = e.getLinkName();
+ linkFlag = e.getLinkFlag();
}
}
diff --git a/src/main/org/apache/tools/tar/TarEntry.java b/src/main/org/apache/tools/tar/TarEntry.java
index d38a8ffd1..ab0212022 100644
--- a/src/main/org/apache/tools/tar/TarEntry.java
+++ b/src/main/org/apache/tools/tar/TarEntry.java
@@ -395,6 +395,24 @@ public class TarEntry implements TarConstants {
this.mode = mode;
}
+ /**
+ * Get this entry's link flag.
+ *
+ * @return This entry's link flag.
+ */
+ public byte getLinkFlag() {
+ return linkFlag;
+ }
+
+ /**
+ * Set this entry's link flag.
+ *
+ * @param link the link flag to use.
+ */
+ public void setLinkFlag(byte linkFlag) {
+ this.linkFlag = linkFlag;
+ }
+
/**
* Get this entry's link name.
*
diff --git a/src/tests/junit/org/apache/tools/ant/taskdefs/TarTest.java b/src/tests/junit/org/apache/tools/ant/taskdefs/TarTest.java
index e37e2b95a..86a6d9beb 100644
--- a/src/tests/junit/org/apache/tools/ant/taskdefs/TarTest.java
+++ b/src/tests/junit/org/apache/tools/ant/taskdefs/TarTest.java
@@ -19,16 +19,21 @@
package org.apache.tools.ant.taskdefs;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.BuildFileRule;
import org.apache.tools.ant.FileUtilities;
+import org.apache.tools.tar.TarEntry;
+import org.apache.tools.tar.TarInputStream;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class TarTest {
@@ -186,4 +191,27 @@ public class TarTest {
public void testtestTarFilesetWithReference() {
buildRule.executeTarget("testTarFilesetWithReference");
}
+
+ @Test
+ public void testTarFilesetWithSymlinks() throws IOException {
+ buildRule.executeTarget("testTarFilesetWithSymlinks");
+ final File f = new File(buildRule.getProject().getProperty("output"), "result.tar");
+ final TarInputStream tis = new TarInputStream(new FileInputStream(f));
+ try {
+ final TarEntry e1 = tis.getNextEntry();
+ assertEquals("pre/dir/file", e1.getName());
+ assertEquals("", e1.getLinkName());
+ assertEquals(48, e1.getLinkFlag());
+
+ final TarEntry e2 = tis.getNextEntry();
+ assertEquals("pre/sub/file", e2.getName());
+ assertEquals("../dir/file", e2.getLinkName());
+ assertEquals(50, e2.getLinkFlag());
+
+ assertNull(tis.getNextEntry());
+ }
+ finally {
+ tis.close();
+ }
+ }
}