[JENKINS-9118]

Tar/untar now correctly supports symlinks.
This commit is contained in:
Kohsuke Kawaguchi committed 2012-03-09 18:26:22 -08:00
1 parent 48daab0f0b
commit d184d53b24
6 files changed
+118 -4

No files matched your search

+71 -2
View File
@@ -46,8 +46,9 @@ import hudson.util.IOException2;
import hudson.util.HeadBufferingStream;
import hudson.util.FormValidation;
import hudson.util.IOUtils;
import static hudson.Util.*;
import static hudson.util.jna.GNUCLibrary.LIBC;
import static hudson.Util.fixEmpty;
import static hudson.FilePath.TarCompression.GZIP;
import hudson.org.apache.tools.tar.TarInputStream;
import hudson.util.io.Archiver;
@@ -75,6 +76,7 @@ import java.io.OutputStream;
import java.io.Serializable;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.lang.reflect.Field;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
@@ -331,6 +333,15 @@ public final class FilePath implements Serializable {
zip(os,(FileFilter)null);
}
public void zip(FilePath dst) throws IOException, InterruptedException {
OutputStream os = dst.write();
try {
zip(os);
} finally {
os.close();
}
}
/**
* Creates a zip file from this directory by using the specified filter,
* and sends the result to the given output stream.
@@ -529,6 +540,39 @@ public final class FilePath implements Serializable {
}));
}
/**
* Creates a symlink to the specified target.
*
* @param target
* The file that the symlink should point to.
* @param listener
* If symlink creation requires a help of an external process, the error will be reported here.
* @since 1.456
*/
public void symlinkTo(final String target, final TaskListener listener) throws IOException, InterruptedException {
act(new FileCallable<Void>() {
public Void invoke(File f, VirtualChannel channel) throws IOException, InterruptedException {
Util.createSymlink(f.getParentFile(),target,f.getName(),listener);
return null;
}
});
}
/**
* Resolves symlink, if the given file is a symlink. Otherwise return null.
* <p>
* If the resolution fails, report an error.
*
* @since 1.456
*/
public String readLink() throws IOException, InterruptedException {
return act(new FileCallable<String>() {
public String invoke(File f, VirtualChannel channel) throws IOException, InterruptedException {
return Util.resolveSymlink(f);
}
});
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -1756,7 +1800,13 @@ public final class FilePath implements Serializable {
File parent = f.getParentFile();
if (parent != null) parent.mkdirs();
IOUtils.copy(t,f);
byte linkFlag = (Byte) LINKFLAG_FIELD.get(te);
if (linkFlag==TarEntry.LF_SYMLINK) {
new FilePath(f).symlinkTo(te.getLinkName(), TaskListener.NULL);
} else {
IOUtils.copy(t,f);
}
f.setLastModified(te.getModTime().getTime());
int mode = te.getMode()&0777;
if(mode!=0 && !Functions.isWindows()) // be defensive
@@ -1765,6 +1815,11 @@ public final class FilePath implements Serializable {
}
} catch(IOException e) {
throw new IOException2("Failed to extract "+name,e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // process this later
throw new IOException2("Failed to extract "+name,e);
} catch (IllegalAccessException e) {
throw new IOException2("Failed to extract "+name,e);
} finally {
t.close();
}
@@ -2124,4 +2179,18 @@ public final class FilePath implements Serializable {
return o1.length()-o2.length();
}
};
private static final Field LINKFLAG_FIELD = getTarEntryLinkFlagField();
private static Field getTarEntryLinkFlagField() {
try {
Field f = TarEntry.class.getDeclaredField("linkFlag");
f.setAccessible(true);
return f;
} catch (SecurityException e) {
throw new AssertionError(e);
} catch (NoSuchFieldException e) {
throw new AssertionError(e);
}
}
}