org.ow2.asm
asm
diff --git a/core/src/main/java/hudson/os/PosixAPI.java b/core/src/main/java/hudson/os/PosixAPI.java
new file mode 100644
index 0000000000..ba1c9aecb9
--- /dev/null
+++ b/core/src/main/java/hudson/os/PosixAPI.java
@@ -0,0 +1,37 @@
+package hudson.os;
+
+import jnr.constants.platform.Errno;
+import jnr.posix.POSIX;
+import jnr.posix.POSIXFactory;
+import jnr.posix.util.DefaultPOSIXHandler;
+
+/**
+ * POSIX API wrapper.
+ * @author Kohsuke Kawaguchi
+ */
+public class PosixAPI {
+
+ private static POSIX posix;
+
+ /**
+ * Load the JNR implementation of the POSIX APIs for the current platform.
+ * Runtime exceptions will be of type {@link PosixException}.
+ * {@link IllegalStateException} will be thrown for methods not implemented on this platform.
+ * @return some implementation (even on Windows or unsupported Unix)
+ * @since 1.518
+ */
+ public static synchronized POSIX jnr() {
+ if (posix == null) {
+ posix = POSIXFactory.getPOSIX(new DefaultPOSIXHandler() {
+ @Override public void error(Errno error, String extraData) {
+ throw new PosixException("native error " + error.description() + " " + extraData);
+ }
+
+ @Override public void error(Errno error, String methodName, String extraData) {
+ throw new PosixException("native error calling " + methodName + ": " + error.description() + " " + extraData);
+ }
+ }, true);
+ }
+ return posix;
+ }
+}
diff --git a/core/src/main/java/hudson/os/PosixException.java b/core/src/main/java/hudson/os/PosixException.java
index be10886825..c32b9a3e6b 100644
--- a/core/src/main/java/hudson/os/PosixException.java
+++ b/core/src/main/java/hudson/os/PosixException.java
@@ -2,6 +2,7 @@ package hudson.os;
/**
* Indicates an error during POSIX API call.
+ * @see PosixAPI
* @author Kohsuke Kawaguchi
*/
public class PosixException extends RuntimeException {
diff --git a/core/src/main/java/hudson/util/jna/GNUCLibrary.java b/core/src/main/java/hudson/util/jna/GNUCLibrary.java
index afa2729d6e..b195e11d04 100644
--- a/core/src/main/java/hudson/util/jna/GNUCLibrary.java
+++ b/core/src/main/java/hudson/util/jna/GNUCLibrary.java
@@ -33,6 +33,8 @@ import com.sun.jna.Pointer;
import com.sun.jna.StringArray;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.NativeLongByReference;
+import hudson.os.PosixAPI;
+import jnr.posix.POSIX;
/**
* GNU C library.
@@ -40,6 +42,7 @@ import com.sun.jna.ptr.NativeLongByReference;
*
* Not available on all platforms (such as Linux/PPC, IBM mainframe, etc.), so the caller should recover gracefully
* in case of {@link LinkageError}. See JENKINS-4820.
+ *
Consider deprecating all methods present also in {@link POSIX} (as obtained by {@link PosixAPI#jnr}).
* @author Kohsuke Kawaguchi
*/
public interface GNUCLibrary extends Library {
diff --git a/core/src/test/java/hudson/FilePathTest.java b/core/src/test/java/hudson/FilePathTest.java
index 33a6e8484b..031537fc46 100644
--- a/core/src/test/java/hudson/FilePathTest.java
+++ b/core/src/test/java/hudson/FilePathTest.java
@@ -40,6 +40,7 @@ import static org.mockito.Mockito.when;
import hudson.FilePath.TarCompression;
import hudson.model.TaskListener;
+import hudson.os.PosixAPI;
import hudson.os.WindowsUtil;
import hudson.remoting.VirtualChannel;
import hudson.slaves.WorkspaceList;
@@ -478,6 +479,25 @@ public class FilePathTest {
}
}
+ @Test public void copyToWithPermissionSpecialPermissions() throws IOException, InterruptedException {
+ assumeFalse(Functions.isWindows() || Platform.isDarwin());
+ File tmp = temp.getRoot();
+ File original = new File(tmp, "original");
+ FilePath originalP = new FilePath(channels.french, original.getPath());
+ originalP.touch(0);
+ PosixAPI.jnr().chmod(original.getAbsolutePath(), 02777); // Read/write/execute for everyone and setuid.
+
+ File sameChannelCopy = new File(tmp, "sameChannelCopy");
+ FilePath sameChannelCopyP = new FilePath(channels.french, sameChannelCopy.getPath());
+ originalP.copyToWithPermission(sameChannelCopyP);
+ assertEquals("Special permissions should be copied on the same machine", 02777, PosixAPI.jnr().stat(sameChannelCopy.getAbsolutePath()).mode() & 07777);
+
+ File diffChannelCopy = new File(tmp, "diffChannelCopy");
+ FilePath diffChannelCopyP = new FilePath(channels.british, diffChannelCopy.getPath());
+ originalP.copyToWithPermission(diffChannelCopyP);
+ assertEquals("Special permissions should not be copied across machines", 00777, PosixAPI.jnr().stat(diffChannelCopy.getAbsolutePath()).mode() & 07777);
+ }
+
@Test public void symlinkInTar() throws Exception {
assumeFalse(Functions.isWindows());