mirror of
https://github.com/jenkinsci/jenkins.git
synced 2026-10-28 20:15:22 +00:00
Merge branch 'SECURITY-144' into SECURITY-144-rc
Conflicts: core/src/main/java/hudson/EnvVars.java core/src/main/java/hudson/FilePath.java core/src/main/java/hudson/cli/ClientAuthenticationCache.java core/src/main/java/hudson/markup/MyspacePolicy.java core/src/main/java/hudson/model/Computer.java core/src/main/java/hudson/node_monitors/DiskSpaceMonitorDescriptor.java core/src/main/java/hudson/node_monitors/ResponseTimeMonitor.java core/src/main/java/hudson/node_monitors/TemporarySpaceMonitor.java core/src/main/java/hudson/security/AbstractPasswordBasedSecurityRealm.java core/src/main/java/hudson/slaves/Channels.java core/src/main/java/hudson/slaves/SlaveComputer.java core/src/main/java/hudson/tasks/Fingerprinter.java core/src/main/java/hudson/tasks/Shell.java core/src/main/java/hudson/tasks/junit/JUnitParser.java core/src/main/java/hudson/tasks/test/DefaultTestResultParserImpl.java core/src/main/java/hudson/util/ProcessTree.java core/src/main/java/hudson/util/RemotingDiagnostics.java core/src/main/java/jenkins/model/Jenkins.java core/src/test/java/hudson/LauncherTest.java pom.xml test/src/test/java/hudson/tasks/junit/CaseResultTest.java
This commit is contained in:
commit
89cbfc4639
60 files changed
+1200
-301
No files matched your search
@@ -112,6 +112,13 @@ import java.util.regex.Pattern;
|
||||
import static hudson.FilePath.TarCompression.*;
|
||||
import static hudson.Util.*;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import jenkins.FilePathFilter;
|
||||
import jenkins.MasterToSlaveFileCallable;
|
||||
import jenkins.SlaveToMasterFileCallable;
|
||||
import jenkins.security.MasterToSlaveCallable;
|
||||
import org.jenkinsci.remoting.RoleChecker;
|
||||
import org.jenkinsci.remoting.RoleSensitive;
|
||||
|
||||
/**
|
||||
* {@link File} like object with remoting support.
|
||||
@@ -197,6 +204,17 @@ public final class FilePath implements Serializable {
|
||||
// since the platform of the slave might be different, can't use java.io.File
|
||||
private final String remote;
|
||||
|
||||
/**
|
||||
* If this {@link FilePath} is deserialized to handle file access request from a remote computer,
|
||||
* this field is set to the filter that performs access control.
|
||||
*
|
||||
* <p>
|
||||
* If null, no access control is needed.
|
||||
*
|
||||
* @see #filterNonNull()
|
||||
*/
|
||||
private transient @Nullable FilePathFilter filter;
|
||||
|
||||
/**
|
||||
* Creates a {@link FilePath} that represents a path on the given node.
|
||||
*
|
||||
@@ -423,11 +441,11 @@ public final class FilePath implements Serializable {
|
||||
*/
|
||||
public int archive(final ArchiverFactory factory, OutputStream os, final DirScanner scanner) throws IOException, InterruptedException {
|
||||
final OutputStream out = (channel!=null)?new RemoteOutputStream(os):os;
|
||||
return act(new FileCallable<Integer>() {
|
||||
return act(new SecureFileCallable<Integer>() {
|
||||
public Integer invoke(File f, VirtualChannel channel) throws IOException {
|
||||
Archiver a = factory.create(out);
|
||||
try {
|
||||
scanner.scan(f,a);
|
||||
scanner.scan(f,reading(a));
|
||||
} finally {
|
||||
a.close();
|
||||
}
|
||||
@@ -455,13 +473,13 @@ public final class FilePath implements Serializable {
|
||||
* @see #unzipFrom(InputStream)
|
||||
*/
|
||||
public void unzip(final FilePath target) throws IOException, InterruptedException {
|
||||
target.act(new FileCallable<Void>() {
|
||||
target.act(new SecureFileCallable<Void>() {
|
||||
|
||||
public Void invoke(File dir, VirtualChannel channel) throws IOException {
|
||||
public Void invoke(File dir, VirtualChannel channel) throws IOException, InterruptedException {
|
||||
if (FilePath.this.isRemote())
|
||||
unzip(dir, FilePath.this.read()); // use streams
|
||||
else
|
||||
unzip(dir, new File(FilePath.this.getRemote())); // shortcut to local file
|
||||
unzip(dir, reading(new File(FilePath.this.getRemote()))); // shortcut to local file
|
||||
return null;
|
||||
}
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -479,8 +497,8 @@ public final class FilePath implements Serializable {
|
||||
* @see #untarFrom(InputStream, TarCompression)
|
||||
*/
|
||||
public void untar(final FilePath target, final TarCompression compression) throws IOException, InterruptedException {
|
||||
target.act(new FileCallable<Void>() {
|
||||
public Void invoke(File dir, VirtualChannel channel) throws IOException {
|
||||
target.act(new SecureFileCallable<Void>() {
|
||||
public Void invoke(File dir, VirtualChannel channel) throws IOException, InterruptedException {
|
||||
readFromTar(FilePath.this.getName(),dir,compression.extract(FilePath.this.read()));
|
||||
return null;
|
||||
}
|
||||
@@ -498,7 +516,7 @@ public final class FilePath implements Serializable {
|
||||
*/
|
||||
public void unzipFrom(InputStream _in) throws IOException, InterruptedException {
|
||||
final InputStream in = new RemoteInputStream(_in);
|
||||
act(new FileCallable<Void>() {
|
||||
act(new SecureFileCallable<Void>() {
|
||||
public Void invoke(File dir, VirtualChannel channel) throws IOException {
|
||||
unzip(dir, in);
|
||||
return null;
|
||||
@@ -507,7 +525,7 @@ public final class FilePath implements Serializable {
|
||||
});
|
||||
}
|
||||
|
||||
private static void unzip(File dir, InputStream in) throws IOException {
|
||||
private void unzip(File dir, InputStream in) throws IOException {
|
||||
File tmpFile = File.createTempFile("tmpzip", null); // uses java.io.tmpdir
|
||||
try {
|
||||
// TODO why does this not simply use ZipInputStream?
|
||||
@@ -519,7 +537,7 @@ public final class FilePath implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
static private void unzip(File dir, File zipFile) throws IOException {
|
||||
private void unzip(File dir, File zipFile) throws IOException {
|
||||
dir = dir.getAbsoluteFile(); // without absolutization, getParentFile below seems to fail
|
||||
ZipFile zip = new ZipFile(zipFile);
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -530,15 +548,15 @@ public final class FilePath implements Serializable {
|
||||
ZipEntry e = entries.nextElement();
|
||||
File f = new File(dir, e.getName());
|
||||
if (e.isDirectory()) {
|
||||
f.mkdirs();
|
||||
mkdirs(f);
|
||||
} else {
|
||||
File p = f.getParentFile();
|
||||
if (p != null) {
|
||||
p.mkdirs();
|
||||
mkdirs(p);
|
||||
}
|
||||
InputStream input = zip.getInputStream(e);
|
||||
try {
|
||||
IOUtils.copy(input, f);
|
||||
IOUtils.copy(input, writing(f));
|
||||
} finally {
|
||||
input.close();
|
||||
}
|
||||
@@ -562,7 +580,7 @@ public final class FilePath implements Serializable {
|
||||
* Absolutizes this {@link FilePath} and returns the new one.
|
||||
*/
|
||||
public FilePath absolutize() throws IOException, InterruptedException {
|
||||
return new FilePath(channel,act(new FileCallable<String>() {
|
||||
return new FilePath(channel,act(new SecureFileCallable<String>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public String invoke(File f, VirtualChannel channel) throws IOException {
|
||||
return f.getAbsolutePath();
|
||||
@@ -580,9 +598,10 @@ public final class FilePath implements Serializable {
|
||||
* @since 1.456
|
||||
*/
|
||||
public void symlinkTo(final String target, final TaskListener listener) throws IOException, InterruptedException {
|
||||
act(new FileCallable<Void>() {
|
||||
act(new SecureFileCallable<Void>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Void invoke(File f, VirtualChannel channel) throws IOException, InterruptedException {
|
||||
writing(f);
|
||||
Util.createSymlink(f.getParentFile(),target,f.getName(),listener);
|
||||
return null;
|
||||
}
|
||||
@@ -597,10 +616,10 @@ public final class FilePath implements Serializable {
|
||||
* @since 1.456
|
||||
*/
|
||||
public String readLink() throws IOException, InterruptedException {
|
||||
return act(new FileCallable<String>() {
|
||||
return act(new SecureFileCallable<String>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public String invoke(File f, VirtualChannel channel) throws IOException, InterruptedException {
|
||||
return Util.resolveSymlink(f);
|
||||
return Util.resolveSymlink(reading(f));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -666,7 +685,7 @@ public final class FilePath implements Serializable {
|
||||
public void untarFrom(InputStream _in, final TarCompression compression) throws IOException, InterruptedException {
|
||||
try {
|
||||
final InputStream in = new RemoteInputStream(_in);
|
||||
act(new FileCallable<Void>() {
|
||||
act(new SecureFileCallable<Void>() {
|
||||
public Void invoke(File dir, VirtualChannel channel) throws IOException {
|
||||
readFromTar("input stream",dir, compression.extract(in));
|
||||
return null;
|
||||
@@ -776,7 +795,8 @@ public final class FilePath implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Unpack implements FileCallable<Void> {
|
||||
// this reads from arbitrary URL
|
||||
private final class Unpack extends MasterToSlaveFileCallable<Void> {
|
||||
private final URL archive;
|
||||
Unpack(URL archive) {
|
||||
this.archive = archive;
|
||||
@@ -845,7 +865,7 @@ public final class FilePath implements Serializable {
|
||||
public void copyFrom(FileItem file) throws IOException, InterruptedException {
|
||||
if(channel==null) {
|
||||
try {
|
||||
file.write(new File(remote));
|
||||
file.write(writing(new File(remote)));
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
@@ -870,9 +890,14 @@ public final class FilePath implements Serializable {
|
||||
* Code that gets executed on the machine where the {@link FilePath} is local.
|
||||
* Used to act on {@link FilePath}.
|
||||
* <strong>Warning:</code> implementations must be serializable, so prefer a static nested class to an inner class.
|
||||
*
|
||||
* <p>
|
||||
* Subtypes would likely want to extend from either {@link MasterToSlaveCallable}
|
||||
* or {@link SlaveToMasterFileCallable}.
|
||||
*
|
||||
* @see FilePath#act(FileCallable)
|
||||
*/
|
||||
public interface FileCallable<T> extends Serializable {
|
||||
public interface FileCallable<T> extends Serializable, RoleSensitive {
|
||||
/**
|
||||
* Performs the computational task on the node where the data is located.
|
||||
*
|
||||
@@ -888,6 +913,15 @@ public final class FilePath implements Serializable {
|
||||
T invoke(File f, VirtualChannel channel) throws IOException, InterruptedException;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link FileCallable}s that can be executed anywhere, including the master.
|
||||
*
|
||||
* The code is the same as {@link SlaveToMasterFileCallable}, but used as a marker to
|
||||
* designate those impls that use {@link FilePathFilter}.
|
||||
*/
|
||||
/*package*/ static abstract class SecureFileCallable<T> extends SlaveToMasterFileCallable<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes some program on the machine that this {@link FilePath} exists,
|
||||
* so that one can perform local file operations.
|
||||
@@ -1023,6 +1057,12 @@ public final class FilePath implements Serializable {
|
||||
throw (IOException)new InterruptedIOException().initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkRoles(RoleChecker checker) throws SecurityException {
|
||||
task.checkRoles(checker);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
};
|
||||
}
|
||||
@@ -1032,7 +1072,7 @@ public final class FilePath implements Serializable {
|
||||
* on which this file is available.
|
||||
*/
|
||||
public URI toURI() throws IOException, InterruptedException {
|
||||
return act(new FileCallable<URI>() {
|
||||
return act(new SecureFileCallable<URI>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public URI invoke(File f, VirtualChannel channel) {
|
||||
return f.toURI();
|
||||
@@ -1070,10 +1110,10 @@ public final class FilePath implements Serializable {
|
||||
* Creates this directory.
|
||||
*/
|
||||
public void mkdirs() throws IOException, InterruptedException {
|
||||
if(!act(new FileCallable<Boolean>() {
|
||||
if(!act(new SecureFileCallable<Boolean>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Boolean invoke(File f, VirtualChannel channel) throws IOException, InterruptedException {
|
||||
if(f.mkdirs() || f.exists())
|
||||
if(mkdirs(f) || f.exists())
|
||||
return true; // OK
|
||||
|
||||
// following Ant <mkdir> task to avoid possible race condition.
|
||||
@@ -1089,10 +1129,10 @@ public final class FilePath implements Serializable {
|
||||
* Deletes this directory, including all its contents recursively.
|
||||
*/
|
||||
public void deleteRecursive() throws IOException, InterruptedException {
|
||||
act(new FileCallable<Void>() {
|
||||
act(new SecureFileCallable<Void>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Void invoke(File f, VirtualChannel channel) throws IOException {
|
||||
Util.deleteRecursive(f);
|
||||
deleteRecursive(deleting(f));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
@@ -1102,15 +1142,38 @@ public final class FilePath implements Serializable {
|
||||
* Deletes all the contents of this directory, but not the directory itself
|
||||
*/
|
||||
public void deleteContents() throws IOException, InterruptedException {
|
||||
act(new FileCallable<Void>() {
|
||||
act(new SecureFileCallable<Void>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Void invoke(File f, VirtualChannel channel) throws IOException {
|
||||
Util.deleteContentsRecursive(f);
|
||||
deleteContentsRecursive(f);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void deleteRecursive(File dir) throws IOException {
|
||||
if(!isSymlink(dir))
|
||||
deleteContentsRecursive(dir);
|
||||
try {
|
||||
deleteFile(deleting(dir));
|
||||
} catch (IOException e) {
|
||||
// if some of the child directories are big, it might take long enough to delete that
|
||||
// it allows others to create new files, causing problemsl ike JENKINS-10113
|
||||
// so give it one more attempt before we give up.
|
||||
if(!isSymlink(dir))
|
||||
deleteContentsRecursive(dir);
|
||||
deleteFile(deleting(dir));
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteContentsRecursive(File file) throws IOException {
|
||||
File[] files = file.listFiles();
|
||||
if(files==null)
|
||||
return; // the directory didn't exist in the first place
|
||||
for (File child : files)
|
||||
deleteRecursive(child);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file name portion except the extension.
|
||||
*
|
||||
@@ -1196,10 +1259,10 @@ public final class FilePath implements Serializable {
|
||||
*/
|
||||
public FilePath createTempFile(final String prefix, final String suffix) throws IOException, InterruptedException {
|
||||
try {
|
||||
return new FilePath(this,act(new FileCallable<String>() {
|
||||
return new FilePath(this,act(new SecureFileCallable<String>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public String invoke(File dir, VirtualChannel channel) throws IOException {
|
||||
File f = File.createTempFile(prefix, suffix, dir);
|
||||
File f = writing(File.createTempFile(prefix, suffix, dir));
|
||||
return f.getName();
|
||||
}
|
||||
}));
|
||||
@@ -1252,22 +1315,22 @@ public final class FilePath implements Serializable {
|
||||
*/
|
||||
public FilePath createTextTempFile(final String prefix, final String suffix, final String contents, final boolean inThisDirectory) throws IOException, InterruptedException {
|
||||
try {
|
||||
return new FilePath(channel,act(new FileCallable<String>() {
|
||||
return new FilePath(channel,act(new SecureFileCallable<String>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public String invoke(File dir, VirtualChannel channel) throws IOException {
|
||||
if(!inThisDirectory)
|
||||
dir = new File(System.getProperty("java.io.tmpdir"));
|
||||
else
|
||||
dir.mkdirs();
|
||||
mkdirs(dir);
|
||||
|
||||
File f;
|
||||
try {
|
||||
f = File.createTempFile(prefix, suffix, dir);
|
||||
f = creating(File.createTempFile(prefix, suffix, dir));
|
||||
} catch (IOException e) {
|
||||
throw new IOException("Failed to create a temporary directory in "+dir,e);
|
||||
}
|
||||
|
||||
Writer w = new FileWriter(f);
|
||||
Writer w = new FileWriter(writing(f));
|
||||
try {
|
||||
w.write(contents);
|
||||
} finally {
|
||||
@@ -1298,7 +1361,7 @@ public final class FilePath implements Serializable {
|
||||
*/
|
||||
public FilePath createTempDir(final String prefix, final String suffix) throws IOException, InterruptedException {
|
||||
try {
|
||||
return new FilePath(this,act(new FileCallable<String>() {
|
||||
return new FilePath(this,act(new SecureFileCallable<String>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public String invoke(File dir, VirtualChannel channel) throws IOException {
|
||||
File f = File.createTempFile(prefix, suffix, dir);
|
||||
@@ -1318,10 +1381,10 @@ public final class FilePath implements Serializable {
|
||||
* @return true, for a modicum of compatibility
|
||||
*/
|
||||
public boolean delete() throws IOException, InterruptedException {
|
||||
act(new FileCallable<Void>() {
|
||||
act(new SecureFileCallable<Void>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Void invoke(File f, VirtualChannel channel) throws IOException {
|
||||
Util.deleteFile(f);
|
||||
Util.deleteFile(deleting(f));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
@@ -1332,10 +1395,10 @@ public final class FilePath implements Serializable {
|
||||
* Checks if the file exists.
|
||||
*/
|
||||
public boolean exists() throws IOException, InterruptedException {
|
||||
return act(new FileCallable<Boolean>() {
|
||||
return act(new SecureFileCallable<Boolean>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Boolean invoke(File f, VirtualChannel channel) throws IOException {
|
||||
return f.exists();
|
||||
return stating(f).exists();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1348,10 +1411,10 @@ public final class FilePath implements Serializable {
|
||||
* @see #touch(long)
|
||||
*/
|
||||
public long lastModified() throws IOException, InterruptedException {
|
||||
return act(new FileCallable<Long>() {
|
||||
return act(new SecureFileCallable<Long>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Long invoke(File f, VirtualChannel channel) throws IOException {
|
||||
return f.lastModified();
|
||||
return stating(f).lastModified();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1362,12 +1425,12 @@ public final class FilePath implements Serializable {
|
||||
* @since 1.299
|
||||
*/
|
||||
public void touch(final long timestamp) throws IOException, InterruptedException {
|
||||
act(new FileCallable<Void>() {
|
||||
act(new SecureFileCallable<Void>() {
|
||||
private static final long serialVersionUID = -5094638816500738429L;
|
||||
public Void invoke(File f, VirtualChannel channel) throws IOException {
|
||||
if(!f.exists())
|
||||
new FileOutputStream(f).close();
|
||||
if(!f.setLastModified(timestamp))
|
||||
new FileOutputStream(creating(f)).close();
|
||||
if(!stating(f).setLastModified(timestamp))
|
||||
throw new IOException("Failed to set the timestamp of "+f+" to "+timestamp);
|
||||
return null;
|
||||
}
|
||||
@@ -1375,10 +1438,10 @@ public final class FilePath implements Serializable {
|
||||
}
|
||||
|
||||
private void setLastModifiedIfPossible(final long timestamp) throws IOException, InterruptedException {
|
||||
String message = act(new FileCallable<String>() {
|
||||
String message = act(new SecureFileCallable<String>() {
|
||||
private static final long serialVersionUID = -828220335793641630L;
|
||||
public String invoke(File f, VirtualChannel channel) throws IOException {
|
||||
if(!f.setLastModified(timestamp)) {
|
||||
if(!writing(f).setLastModified(timestamp)) {
|
||||
if (Functions.isWindows()) {
|
||||
// On Windows this seems to fail often. See JENKINS-11073
|
||||
// Therefore don't fail, but just log a warning
|
||||
@@ -1400,10 +1463,10 @@ public final class FilePath implements Serializable {
|
||||
* Checks if the file is a directory.
|
||||
*/
|
||||
public boolean isDirectory() throws IOException, InterruptedException {
|
||||
return act(new FileCallable<Boolean>() {
|
||||
return act(new SecureFileCallable<Boolean>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Boolean invoke(File f, VirtualChannel channel) throws IOException {
|
||||
return f.isDirectory();
|
||||
return stating(f).isDirectory();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1414,10 +1477,10 @@ public final class FilePath implements Serializable {
|
||||
* @since 1.129
|
||||
*/
|
||||
public long length() throws IOException, InterruptedException {
|
||||
return act(new FileCallable<Long>() {
|
||||
return act(new SecureFileCallable<Long>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Long invoke(File f, VirtualChannel channel) throws IOException {
|
||||
return f.length();
|
||||
return stating(f).length();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1427,7 +1490,7 @@ public final class FilePath implements Serializable {
|
||||
* @since 1.542
|
||||
*/
|
||||
public long getFreeDiskSpace() throws IOException, InterruptedException {
|
||||
return act(new FileCallable<Long>() {
|
||||
return act(new SecureFileCallable<Long>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Override public Long invoke(File f, VirtualChannel channel) throws IOException {
|
||||
return f.getFreeSpace();
|
||||
@@ -1440,7 +1503,7 @@ public final class FilePath implements Serializable {
|
||||
* @since 1.542
|
||||
*/
|
||||
public long getTotalDiskSpace() throws IOException, InterruptedException {
|
||||
return act(new FileCallable<Long>() {
|
||||
return act(new SecureFileCallable<Long>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Override public Long invoke(File f, VirtualChannel channel) throws IOException {
|
||||
return f.getTotalSpace();
|
||||
@@ -1453,7 +1516,7 @@ public final class FilePath implements Serializable {
|
||||
* @since 1.542
|
||||
*/
|
||||
public long getUsableDiskSpace() throws IOException, InterruptedException {
|
||||
return act(new FileCallable<Long>() {
|
||||
return act(new SecureFileCallable<Long>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Override public Long invoke(File f, VirtualChannel channel) throws IOException {
|
||||
return f.getUsableSpace();
|
||||
@@ -1478,10 +1541,10 @@ public final class FilePath implements Serializable {
|
||||
*/
|
||||
public void chmod(final int mask) throws IOException, InterruptedException {
|
||||
if(!isUnix() || mask==-1) return;
|
||||
act(new FileCallable<Void>() {
|
||||
act(new SecureFileCallable<Void>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Void invoke(File f, VirtualChannel channel) throws IOException {
|
||||
_chmod(f, mask);
|
||||
_chmod(writing(f), mask);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -1509,10 +1572,10 @@ public final class FilePath implements Serializable {
|
||||
*/
|
||||
public int mode() throws IOException, InterruptedException, PosixException {
|
||||
if(!isUnix()) return -1;
|
||||
return act(new FileCallable<Integer>() {
|
||||
return act(new SecureFileCallable<Integer>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Integer invoke(File f, VirtualChannel channel) throws IOException {
|
||||
return IOUtils.mode(f);
|
||||
return IOUtils.mode(stating(f));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1556,10 +1619,10 @@ public final class FilePath implements Serializable {
|
||||
if (filter != null && !(filter instanceof Serializable)) {
|
||||
throw new IllegalArgumentException("Non-serializable filter of " + filter.getClass());
|
||||
}
|
||||
return act(new FileCallable<List<FilePath>>() {
|
||||
return act(new SecureFileCallable<List<FilePath>>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public List<FilePath> invoke(File f, VirtualChannel channel) throws IOException {
|
||||
File[] children = f.listFiles(filter);
|
||||
File[] children = reading(f).listFiles(filter);
|
||||
if(children ==null) return null;
|
||||
|
||||
ArrayList<FilePath> r = new ArrayList<FilePath>(children.length);
|
||||
@@ -1609,10 +1672,10 @@ public final class FilePath implements Serializable {
|
||||
* @since 1.465
|
||||
*/
|
||||
public FilePath[] list(final String includes, final String excludes, final boolean defaultExcludes) throws IOException, InterruptedException {
|
||||
return act(new FileCallable<FilePath[]>() {
|
||||
return act(new SecureFileCallable<FilePath[]>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public FilePath[] invoke(File f, VirtualChannel channel) throws IOException {
|
||||
String[] files = glob(f, includes, excludes, defaultExcludes);
|
||||
String[] files = glob(reading(f), includes, excludes, defaultExcludes);
|
||||
|
||||
FilePath[] r = new FilePath[files.length];
|
||||
for( int i=0; i<r.length; i++ )
|
||||
@@ -1642,18 +1705,20 @@ public final class FilePath implements Serializable {
|
||||
/**
|
||||
* Reads this file.
|
||||
*/
|
||||
public InputStream read() throws IOException {
|
||||
public InputStream read() throws IOException, InterruptedException {
|
||||
if(channel==null)
|
||||
return new FileInputStream(new File(remote));
|
||||
return new FileInputStream(reading(new File(remote)));
|
||||
|
||||
final Pipe p = Pipe.createRemoteToLocal();
|
||||
channel.callAsync(new Callable<Void,IOException>() {
|
||||
actAsync(new SecureFileCallable<Void>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Void call() throws IOException {
|
||||
FileInputStream fis=null;
|
||||
|
||||
@Override
|
||||
public Void invoke(File f, VirtualChannel channel) throws IOException, InterruptedException {
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(new File(remote));
|
||||
Util.copyStream(fis,p.getOut());
|
||||
fis = new FileInputStream(reading(f));
|
||||
Util.copyStream(fis, p.getOut());
|
||||
return null;
|
||||
} finally {
|
||||
org.apache.commons.io.IOUtils.closeQuietly(fis);
|
||||
@@ -1668,7 +1733,7 @@ public final class FilePath implements Serializable {
|
||||
/**
|
||||
* Reads this file into a string, by using the current system encoding.
|
||||
*/
|
||||
public String readToString() throws IOException {
|
||||
public String readToString() throws IOException, InterruptedException {
|
||||
InputStream in = read();
|
||||
try {
|
||||
return org.apache.commons.io.IOUtils.toString(in);
|
||||
@@ -1695,16 +1760,16 @@ public final class FilePath implements Serializable {
|
||||
public OutputStream write() throws IOException, InterruptedException {
|
||||
if(channel==null) {
|
||||
File f = new File(remote).getAbsoluteFile();
|
||||
f.getParentFile().mkdirs();
|
||||
return new FileOutputStream(f);
|
||||
mkdirs(f.getParentFile());
|
||||
return new FileOutputStream(writing(f));
|
||||
}
|
||||
|
||||
return channel.call(new Callable<OutputStream,IOException>() {
|
||||
return act(new SecureFileCallable<OutputStream>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public OutputStream call() throws IOException {
|
||||
File f = new File(remote).getAbsoluteFile();
|
||||
f.getParentFile().mkdirs();
|
||||
FileOutputStream fos = new FileOutputStream(f);
|
||||
public OutputStream invoke(File f, VirtualChannel channel) throws IOException, InterruptedException {
|
||||
f = f.getAbsoluteFile();
|
||||
mkdirs(f.getParentFile());
|
||||
FileOutputStream fos = new FileOutputStream(writing(f));
|
||||
return new RemoteOutputStream(fos);
|
||||
}
|
||||
});
|
||||
@@ -1718,11 +1783,11 @@ public final class FilePath implements Serializable {
|
||||
* @since 1.105
|
||||
*/
|
||||
public void write(final String content, final String encoding) throws IOException, InterruptedException {
|
||||
act(new FileCallable<Void>() {
|
||||
act(new SecureFileCallable<Void>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Void invoke(File f, VirtualChannel channel) throws IOException {
|
||||
f.getParentFile().mkdirs();
|
||||
FileOutputStream fos = new FileOutputStream(f);
|
||||
mkdirs(f.getParentFile());
|
||||
FileOutputStream fos = new FileOutputStream(writing(f));
|
||||
Writer w = encoding != null ? new OutputStreamWriter(fos, encoding) : new OutputStreamWriter(fos);
|
||||
try {
|
||||
w.write(content);
|
||||
@@ -1739,10 +1804,10 @@ public final class FilePath implements Serializable {
|
||||
* @see Util#getDigestOf(File)
|
||||
*/
|
||||
public String digest() throws IOException, InterruptedException {
|
||||
return act(new FileCallable<String>() {
|
||||
return act(new SecureFileCallable<String>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public String invoke(File f, VirtualChannel channel) throws IOException {
|
||||
return Util.getDigestOf(f);
|
||||
return Util.getDigestOf(reading(f));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1755,10 +1820,10 @@ public final class FilePath implements Serializable {
|
||||
if(this.channel != target.channel) {
|
||||
throw new IOException("renameTo target must be on the same host");
|
||||
}
|
||||
act(new FileCallable<Void>() {
|
||||
act(new SecureFileCallable<Void>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Void invoke(File f, VirtualChannel channel) throws IOException {
|
||||
f.renameTo(new File(target.remote));
|
||||
reading(f).renameTo(creating(new File(target.remote)));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
@@ -1773,7 +1838,7 @@ public final class FilePath implements Serializable {
|
||||
if(this.channel != target.channel) {
|
||||
throw new IOException("pullUpTo target must be on the same host");
|
||||
}
|
||||
act(new FileCallable<Void>() {
|
||||
act(new SecureFileCallable<Void>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Void invoke(File f, VirtualChannel channel) throws IOException {
|
||||
// JENKINS-16846: if f.getName() is the same as one of the files/directories in f,
|
||||
@@ -1784,12 +1849,12 @@ public final class FilePath implements Serializable {
|
||||
|
||||
File t = new File(target.getRemote());
|
||||
|
||||
for(File child : tmp.listFiles()) {
|
||||
for(File child : reading(tmp).listFiles()) {
|
||||
File target = new File(t, child.getName());
|
||||
if(!child.renameTo(target))
|
||||
if(!stating(child).renameTo(creating(target)))
|
||||
throw new IOException("Failed to rename "+child+" to "+target);
|
||||
}
|
||||
tmp.delete();
|
||||
deleting(tmp).delete();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
@@ -1828,12 +1893,12 @@ public final class FilePath implements Serializable {
|
||||
public void copyTo(OutputStream os) throws IOException, InterruptedException {
|
||||
final OutputStream out = new RemoteOutputStream(os);
|
||||
|
||||
act(new FileCallable<Void>() {
|
||||
act(new SecureFileCallable<Void>() {
|
||||
private static final long serialVersionUID = 4088559042349254141L;
|
||||
public Void invoke(File f, VirtualChannel channel) throws IOException {
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(f);
|
||||
fis = new FileInputStream(reading(f));
|
||||
Util.copyStream(fis,out);
|
||||
return null;
|
||||
} finally {
|
||||
@@ -1875,21 +1940,6 @@ public final class FilePath implements Serializable {
|
||||
channel.syncLocalIO();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remoting interface used for {@link FilePath#copyRecursiveTo(String, FilePath)}.
|
||||
*
|
||||
* TODO: this might not be the most efficient way to do the copy.
|
||||
*/
|
||||
interface RemoteCopier {
|
||||
/**
|
||||
* @param fileName
|
||||
* relative path name to the output file. Path separator must be '/'.
|
||||
*/
|
||||
void open(String fileName) throws IOException;
|
||||
void write(byte[] buf, int len) throws IOException;
|
||||
void close() throws IOException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the contents of this directory recursively into the specified target directory.
|
||||
*
|
||||
@@ -1944,35 +1994,41 @@ public final class FilePath implements Serializable {
|
||||
public int copyRecursiveTo(final DirScanner scanner, final FilePath target, final String description) throws IOException, InterruptedException {
|
||||
if(this.channel==target.channel) {
|
||||
// local to local copy.
|
||||
return act(new FileCallable<Integer>() {
|
||||
return act(new SecureFileCallable<Integer>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Integer invoke(File base, VirtualChannel channel) throws IOException {
|
||||
if(!base.exists()) return 0;
|
||||
assert target.channel==null;
|
||||
final File dest = new File(target.remote);
|
||||
final AtomicInteger count = new AtomicInteger();
|
||||
scanner.scan(base, new FileVisitor() {
|
||||
@Override public void visit(File f, String relativePath) throws IOException {
|
||||
scanner.scan(base, reading(new FileVisitor() {
|
||||
@Override
|
||||
public void visit(File f, String relativePath) throws IOException {
|
||||
if (f.isFile()) {
|
||||
File target = new File(dest, relativePath);
|
||||
IOUtils.mkdirs(target.getParentFile());
|
||||
Util.copyFile(f, target);
|
||||
mkdirsE(target.getParentFile());
|
||||
Util.copyFile(f, writing(target));
|
||||
count.incrementAndGet();
|
||||
}
|
||||
}
|
||||
@Override public boolean understandsSymlink() {
|
||||
|
||||
@Override
|
||||
public boolean understandsSymlink() {
|
||||
return true;
|
||||
}
|
||||
@Override public void visitSymlink(File link, String target, String relativePath) throws IOException {
|
||||
|
||||
@Override
|
||||
public void visitSymlink(File link, String target, String relativePath) throws IOException {
|
||||
try {
|
||||
IOUtils.mkdirs(new File(dest, relativePath).getParentFile());
|
||||
mkdirsE(new File(dest, relativePath).getParentFile());
|
||||
writing(new File(dest, target));
|
||||
Util.createSymlink(dest, target, relativePath, TaskListener.NULL);
|
||||
} catch (InterruptedException x) {
|
||||
throw (IOException) new IOException(x.toString()).initCause(x);
|
||||
}
|
||||
count.incrementAndGet();
|
||||
}
|
||||
});
|
||||
}));
|
||||
return count.get();
|
||||
}
|
||||
});
|
||||
@@ -1981,7 +2037,7 @@ public final class FilePath implements Serializable {
|
||||
// local -> remote copy
|
||||
final Pipe pipe = Pipe.createLocalToRemote();
|
||||
|
||||
Future<Void> future = target.actAsync(new FileCallable<Void>() {
|
||||
Future<Void> future = target.actAsync(new SecureFileCallable<Void>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Void invoke(File f, VirtualChannel channel) throws IOException {
|
||||
try {
|
||||
@@ -1992,7 +2048,7 @@ public final class FilePath implements Serializable {
|
||||
}
|
||||
}
|
||||
});
|
||||
Future<Integer> future2 = actAsync(new FileCallable<Integer>() {
|
||||
Future<Integer> future2 = actAsync(new SecureFileCallable<Integer>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Override public Integer invoke(File f, VirtualChannel channel) throws IOException, InterruptedException {
|
||||
return writeToTar(new File(remote), scanner, TarCompression.GZIP.compress(pipe.getOut()));
|
||||
@@ -2009,7 +2065,7 @@ public final class FilePath implements Serializable {
|
||||
// remote -> local copy
|
||||
final Pipe pipe = Pipe.createRemoteToLocal();
|
||||
|
||||
Future<Integer> future = actAsync(new FileCallable<Integer>() {
|
||||
Future<Integer> future = actAsync(new SecureFileCallable<Integer>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Integer invoke(File f, VirtualChannel channel) throws IOException {
|
||||
try {
|
||||
@@ -2069,10 +2125,10 @@ public final class FilePath implements Serializable {
|
||||
* @return
|
||||
* number of files/directories that are written.
|
||||
*/
|
||||
private static Integer writeToTar(File baseDir, DirScanner scanner, OutputStream out) throws IOException {
|
||||
private Integer writeToTar(File baseDir, DirScanner scanner, OutputStream out) throws IOException {
|
||||
Archiver tw = ArchiverFactory.TAR.create(out);
|
||||
try {
|
||||
scanner.scan(baseDir,tw);
|
||||
scanner.scan(baseDir,reading(tw));
|
||||
} finally {
|
||||
tw.close();
|
||||
}
|
||||
@@ -2082,17 +2138,18 @@ public final class FilePath implements Serializable {
|
||||
/**
|
||||
* Reads from a tar stream and stores obtained files to the base dir.
|
||||
*/
|
||||
private static void readFromTar(String name, File baseDir, InputStream in) throws IOException {
|
||||
private void readFromTar(String name, File baseDir, InputStream in) throws IOException {
|
||||
TarInputStream t = new TarInputStream(in);
|
||||
try {
|
||||
TarEntry te;
|
||||
while ((te = t.getNextEntry()) != null) {
|
||||
File f = new File(baseDir,te.getName());
|
||||
if(te.isDirectory()) {
|
||||
f.mkdirs();
|
||||
mkdirs(f);
|
||||
} else {
|
||||
File parent = f.getParentFile();
|
||||
if (parent != null) parent.mkdirs();
|
||||
if (parent != null) mkdirs(parent);
|
||||
writing(f);
|
||||
|
||||
byte linkFlag = (Byte) LINKFLAG_FIELD.get(te);
|
||||
if (linkFlag==TarEntry.LF_SYMLINK) {
|
||||
@@ -2131,7 +2188,7 @@ public final class FilePath implements Serializable {
|
||||
return new RemoteLauncher(listener,channel,channel.call(new IsUnix()));
|
||||
}
|
||||
|
||||
private static final class IsUnix implements Callable<Boolean,IOException> {
|
||||
private static final class IsUnix extends MasterToSlaveCallable<Boolean,IOException> {
|
||||
public Boolean call() throws IOException {
|
||||
return File.pathSeparatorChar==':';
|
||||
}
|
||||
@@ -2168,7 +2225,7 @@ public final class FilePath implements Serializable {
|
||||
* @since 1.484
|
||||
*/
|
||||
public String validateAntFileMask(final String fileMasks, final int bound) throws IOException, InterruptedException {
|
||||
return act(new FileCallable<String>() {
|
||||
return act(new MasterToSlaveFileCallable<String>() {
|
||||
private static final long serialVersionUID = 1;
|
||||
public String invoke(File dir, VirtualChannel channel) throws IOException, InterruptedException {
|
||||
if(fileMasks.startsWith("~"))
|
||||
@@ -2209,7 +2266,7 @@ public final class FilePath implements Serializable {
|
||||
|
||||
{// check the (2) above next as this is more expensive.
|
||||
// Try prepending "**/" to see if that results in a match
|
||||
FileSet fs = Util.createFileSet(dir,"**/"+fileMask);
|
||||
FileSet fs = Util.createFileSet(reading(dir),"**/"+fileMask);
|
||||
DirectoryScanner ds = fs.getDirectoryScanner(new Project());
|
||||
if(ds.getIncludedFilesCount()!=0) {
|
||||
// try shorter name first so that the suggestion results in least amount of changes
|
||||
@@ -2278,7 +2335,7 @@ public final class FilePath implements Serializable {
|
||||
return super.isCaseSensitive();
|
||||
}
|
||||
};
|
||||
ds.setBasedir(dir);
|
||||
ds.setBasedir(reading(dir));
|
||||
ds.setIncludes(new String[] {pattern});
|
||||
try {
|
||||
ds.scan();
|
||||
@@ -2451,8 +2508,14 @@ public final class FilePath implements Serializable {
|
||||
ois.defaultReadObject();
|
||||
if(ois.readBoolean()) {
|
||||
this.channel = channel;
|
||||
this.filter = null;
|
||||
} else {
|
||||
this.channel = null;
|
||||
// If the remote channel wants us to create a FilePath that points to a local file,
|
||||
// we need to make sure the access control takes place.
|
||||
// This covers the immediate case of FileCallables taking FilePath into reference closure implicitly,
|
||||
// but it also covers more general case of FilePath sent as a return value or argument.
|
||||
this.filter = FilePathFilter.current();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2487,6 +2550,14 @@ public final class FilePath implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Role check comes from {@link FileCallable}s.
|
||||
*/
|
||||
@Override
|
||||
public void checkRoles(RoleChecker checker) throws SecurityException {
|
||||
callable.checkRoles(checker);
|
||||
}
|
||||
|
||||
public ClassLoader getClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
@@ -2529,7 +2600,7 @@ public final class FilePath implements Serializable {
|
||||
* (User's home directory in the Unix sense) of the given channel.
|
||||
*/
|
||||
public static FilePath getHomeDirectory(VirtualChannel ch) throws InterruptedException, IOException {
|
||||
return ch.call(new Callable<FilePath,IOException>() {
|
||||
return ch.call(new MasterToSlaveCallable<FilePath,IOException>() {
|
||||
public FilePath call() throws IOException {
|
||||
return new FilePath(new File(System.getProperty("user.home")));
|
||||
}
|
||||
@@ -2563,7 +2634,6 @@ public final class FilePath implements Serializable {
|
||||
scanSingle(new File(dir, workspacePath), archivedPath, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final ExecutorService threadPoolForRemoting = new ContextResettingExecutorService(
|
||||
@@ -2573,4 +2643,93 @@ public final class FilePath implements Serializable {
|
||||
));
|
||||
|
||||
public static final LocalChannel localChannel = new LocalChannel(threadPoolForRemoting);
|
||||
|
||||
private @Nonnull FilePathFilter filterNonNull() {
|
||||
return filter!=null ? filter : FilePathFilter.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link FileVisitor} to notify read access to {@link FilePathFilter}.
|
||||
*/
|
||||
private FileVisitor reading(final FileVisitor v) {
|
||||
final FilePathFilter filter = FilePathFilter.current();
|
||||
if (filter==null) return v;
|
||||
|
||||
return new FileVisitor() {
|
||||
@Override
|
||||
public void visit(File f, String relativePath) throws IOException {
|
||||
filter.read(f);
|
||||
v.visit(f,relativePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSymlink(File link, String target, String relativePath) throws IOException {
|
||||
filter.read(link);
|
||||
v.visitSymlink(link, target, relativePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean understandsSymlink() {
|
||||
return v.understandsSymlink();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass through 'f' after ensuring that we can read that file.
|
||||
*/
|
||||
private File reading(File f) {
|
||||
filterNonNull().read(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass through 'f' after ensuring that we can access the file attributes.
|
||||
*/
|
||||
private File stating(File f) {
|
||||
filterNonNull().stat(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass through 'f' after ensuring that we can create that file/dir.
|
||||
*/
|
||||
private File creating(File f) {
|
||||
filterNonNull().create(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass through 'f' after ensuring that we can write to that file.
|
||||
*/
|
||||
private File writing(File f) {
|
||||
FilePathFilter filter = filterNonNull();
|
||||
if (!f.exists())
|
||||
filter.create(f);
|
||||
filter.write(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass through 'f' after ensuring that we can delete that file.
|
||||
*/
|
||||
private File deleting(File f) {
|
||||
filterNonNull().delete(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
private boolean mkdirs(File dir) {
|
||||
if (dir.exists()) return false;
|
||||
|
||||
filterNonNull().mkdirs(dir);
|
||||
return dir.mkdirs();
|
||||
}
|
||||
|
||||
private File mkdirsE(File dir) throws IOException {
|
||||
if (dir.exists()) {
|
||||
return dir;
|
||||
}
|
||||
filterNonNull().mkdirs(dir);
|
||||
return IOUtils.mkdirs(dir);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user