mirror of
https://github.com/jenkinsci/jenkins.git
synced 2026-11-15 13:02:19 +00:00
Merge branch 'master' into surefire-mixup
This commit is contained in:
11 files changed
+259
-64
No files matched your search
@@ -79,6 +79,7 @@ import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
@@ -1582,6 +1583,11 @@ public final class FilePath implements Serializable {
|
||||
* <p>
|
||||
* please note mask is expected to be an octal if you use <a href="http://en.wikipedia.org/wiki/Chmod">chmod command line values</a>,
|
||||
* so preceded by a '0' in java notation, ie <code>chmod(0644)</code>
|
||||
* <p>
|
||||
* Only supports setting read, write, or execute permissions for the
|
||||
* owner, group, or others, so the largest permissible value is 0777.
|
||||
* Attempting to set larger values (i.e. the setgid, setuid, or sticky
|
||||
* bits) will cause an IOException to be thrown.
|
||||
*
|
||||
* @since 1.303
|
||||
* @see #mode()
|
||||
@@ -1591,7 +1597,6 @@ public final class FilePath implements Serializable {
|
||||
act(new SecureFileCallable<Void>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public Void invoke(File f, VirtualChannel channel) throws IOException {
|
||||
// TODO first check for Java 7+ and use PosixFileAttributeView
|
||||
_chmod(writing(f), mask);
|
||||
|
||||
return null;
|
||||
@@ -1600,14 +1605,18 @@ public final class FilePath implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Run chmod via jnr-posix
|
||||
* Change permissions via NIO.
|
||||
*/
|
||||
private static void _chmod(File f, int mask) throws IOException {
|
||||
// TODO WindowsPosix actually does something here (WindowsLibC._wchmod); should we let it?
|
||||
// Anyway the existing calls already skip this method if on Windows.
|
||||
if (File.pathSeparatorChar==';') return; // noop
|
||||
|
||||
PosixAPI.jnr().chmod(f.getAbsolutePath(),mask);
|
||||
if (Util.NATIVE_CHMOD_MODE) {
|
||||
PosixAPI.jnr().chmod(f.getAbsolutePath(), mask);
|
||||
} else {
|
||||
Files.setPosixFilePermissions(Util.fileToPath(f), Util.modeToPermissions(mask));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean CHMOD_WARNED = false;
|
||||
@@ -2008,6 +2017,21 @@ public final class FilePath implements Serializable {
|
||||
* @since 1.311
|
||||
*/
|
||||
public void copyToWithPermission(FilePath target) throws IOException, InterruptedException {
|
||||
// Use NIO copy with StandardCopyOption.COPY_ATTRIBUTES when copying on the same machine.
|
||||
if (this.channel == target.channel) {
|
||||
act(new SecureFileCallable<Void>() {
|
||||
public Void invoke(File f, VirtualChannel channel) throws IOException {
|
||||
File targetFile = new File(target.remote);
|
||||
File targetDir = targetFile.getParentFile();
|
||||
filterNonNull().mkdirs(targetDir);
|
||||
Files.createDirectories(Util.fileToPath(targetDir));
|
||||
Files.copy(Util.fileToPath(reading(f)), Util.fileToPath(writing(targetFile)), StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
copyTo(target);
|
||||
// copy file permission
|
||||
target.chmod(mode());
|
||||
|
||||
@@ -125,6 +125,7 @@ import java.util.logging.Logger;
|
||||
import java.util.logging.SimpleFormatter;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -1142,13 +1143,17 @@ public class Functions {
|
||||
* Gets the relative name or display name to the given item from the specified group.
|
||||
*
|
||||
* @since 1.515
|
||||
* @param p the Item we want the relative display name
|
||||
* @param g the ItemGroup used as point of reference for the item
|
||||
* @param p the Item we want the relative display name.
|
||||
* If {@code null}, a {@code null} will be returned by the method
|
||||
* @param g the ItemGroup used as point of reference for the item.
|
||||
* If the group is not specified, item's path will be used.
|
||||
* @param useDisplayName if true, returns a display name, otherwise returns a name
|
||||
* @return
|
||||
* String like "foo » bar"
|
||||
* String like "foo » bar".
|
||||
* {@code null} if item is null or if one of its parents is not an {@link Item}.
|
||||
*/
|
||||
public static String getRelativeNameFrom(Item p, ItemGroup g, boolean useDisplayName) {
|
||||
@Nullable
|
||||
public static String getRelativeNameFrom(@CheckForNull Item p, @CheckForNull ItemGroup g, boolean useDisplayName) {
|
||||
if (p == null) return null;
|
||||
if (g == null) return useDisplayName ? p.getFullDisplayName() : p.getFullName();
|
||||
String separationString = useDisplayName ? " » " : "/";
|
||||
@@ -1182,7 +1187,7 @@ public class Functions {
|
||||
|
||||
if (gr instanceof Item)
|
||||
i = (Item)gr;
|
||||
else
|
||||
else // Parent is a group, but not an item
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1192,11 +1197,14 @@ public class Functions {
|
||||
*
|
||||
* @since 1.515
|
||||
* @param p the Item we want the relative display name
|
||||
* If {@code null}, the method will immediately return {@code null}.
|
||||
* @param g the ItemGroup used as point of reference for the item
|
||||
* @return
|
||||
* String like "foo/bar"
|
||||
* String like "foo/bar".
|
||||
* {@code null} if the item is {@code null} or if one of its parents is not an {@link Item}.
|
||||
*/
|
||||
public static String getRelativeNameFrom(Item p, ItemGroup g) {
|
||||
@Nullable
|
||||
public static String getRelativeNameFrom(@CheckForNull Item p, @CheckForNull ItemGroup g) {
|
||||
return getRelativeNameFrom(p, g, false);
|
||||
}
|
||||
|
||||
@@ -1205,12 +1213,15 @@ public class Functions {
|
||||
* Gets the relative display name to the given item from the specified group.
|
||||
*
|
||||
* @since 1.512
|
||||
* @param p the Item we want the relative display name
|
||||
* @param p the Item we want the relative display name.
|
||||
* If {@code null}, the method will immediately return {@code null}.
|
||||
* @param g the ItemGroup used as point of reference for the item
|
||||
* @return
|
||||
* String like "Foo » Bar"
|
||||
* String like "Foo » Bar".
|
||||
* {@code null} if the item is {@code null} or if one of its parents is not an {@link Item}.
|
||||
*/
|
||||
public static String getRelativeDisplayNameFrom(Item p, ItemGroup g) {
|
||||
@Nullable
|
||||
public static String getRelativeDisplayNameFrom(@CheckForNull Item p, @CheckForNull ItemGroup g) {
|
||||
return getRelativeNameFrom(p, g, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ import java.nio.file.LinkOption;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.nio.file.attribute.DosFileAttributes;
|
||||
import java.security.MessageDigest;
|
||||
@@ -1597,6 +1598,51 @@ public class Util {
|
||||
}
|
||||
}
|
||||
|
||||
@Restricted(NoExternalUse.class)
|
||||
public static int permissionsToMode(Set<PosixFilePermission> permissions) {
|
||||
PosixFilePermission[] allPermissions = PosixFilePermission.values();
|
||||
int result = 0;
|
||||
for (int i = 0; i < allPermissions.length; i++) {
|
||||
result <<= 1;
|
||||
result |= permissions.contains(allPermissions[i]) ? 1 : 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Restricted(NoExternalUse.class)
|
||||
public static Set<PosixFilePermission> modeToPermissions(int mode) throws IOException {
|
||||
// Anything larger is a file type, not a permission.
|
||||
int PERMISSIONS_MASK = 07777;
|
||||
// setgid/setuid/sticky are not supported.
|
||||
int MAX_SUPPORTED_MODE = 0777;
|
||||
mode = mode & PERMISSIONS_MASK;
|
||||
if ((mode & MAX_SUPPORTED_MODE) != mode) {
|
||||
throw new IOException("Invalid mode: " + mode);
|
||||
}
|
||||
PosixFilePermission[] allPermissions = PosixFilePermission.values();
|
||||
Set<PosixFilePermission> result = EnumSet.noneOf(PosixFilePermission.class);
|
||||
for (int i = 0; i < allPermissions.length; i++) {
|
||||
if ((mode & 1) == 1) {
|
||||
result.add(allPermissions[allPermissions.length - i - 1]);
|
||||
}
|
||||
mode >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link File} into a {@link Path} and checks runtime exceptions.
|
||||
* @throws IOException if {@code f.toPath()} throws {@link InvalidPathException}.
|
||||
*/
|
||||
@Restricted(NoExternalUse.class)
|
||||
public static @Nonnull Path fileToPath(@Nonnull File file) throws IOException {
|
||||
try {
|
||||
return file.toPath();
|
||||
} catch (InvalidPathException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final FastDateFormat XS_DATETIME_FORMATTER = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss'Z'",new SimpleTimeZone(0,"GMT"));
|
||||
|
||||
// Note: RFC822 dates must not be localized!
|
||||
@@ -1664,4 +1710,15 @@ public class Util {
|
||||
*/
|
||||
@Restricted(value = NoExternalUse.class)
|
||||
static boolean GC_AFTER_FAILED_DELETE = SystemProperties.getBoolean(Util.class.getName() + ".performGCOnFailedDelete");
|
||||
|
||||
/**
|
||||
* If this flag is true, native implementations of {@link FilePath#chmod}
|
||||
* and {@link hudson.util.IOUtils#mode} are used instead of NIO.
|
||||
* <p>
|
||||
* This should only be enabled if the setgid/setuid/sticky bits are
|
||||
* intentionally set on the Jenkins installation and they are being
|
||||
* overwritten by Jenkins erroneously.
|
||||
*/
|
||||
@Restricted(value = NoExternalUse.class)
|
||||
public static boolean NATIVE_CHMOD_MODE = SystemProperties.getBoolean(Util.class.getName() + ".useNativeChmodAndMode");
|
||||
}
|
||||
@@ -381,21 +381,6 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet
|
||||
return getRelativeNameFrom(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param p
|
||||
* The ItemGroup instance used as context to evaluate the relative name of this AbstractItem
|
||||
* @return
|
||||
* The name of the current item, relative to p.
|
||||
* Nested ItemGroups are separated by / character.
|
||||
*/
|
||||
public String getRelativeNameFrom(ItemGroup p) {
|
||||
return Functions.getRelativeNameFrom(this, p);
|
||||
}
|
||||
|
||||
public String getRelativeNameFrom(Item item) {
|
||||
return getRelativeNameFrom(item.getParent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Called right after when a {@link Item} is loaded from disk.
|
||||
* This is an opportunity to do a post load processing.
|
||||
@@ -470,12 +455,10 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet
|
||||
return getShortUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Exported(visibility=999,name="url")
|
||||
public final String getAbsoluteUrl() {
|
||||
String r = Jenkins.getInstance().getRootUrl();
|
||||
if(r==null)
|
||||
throw new IllegalStateException("Root URL isn't configured yet. Cannot compute absolute URL.");
|
||||
return Util.encode(r+getUrl());
|
||||
return Item.super.getAbsoluteUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,13 +40,19 @@ public interface BuildableItem extends Item, Task {
|
||||
* Use {@link #scheduleBuild(Cause)}. Since 1.283
|
||||
*/
|
||||
@Deprecated
|
||||
boolean scheduleBuild();
|
||||
default boolean scheduleBuild() {
|
||||
return scheduleBuild(new Cause.LegacyCodeCause());
|
||||
}
|
||||
|
||||
boolean scheduleBuild(Cause c);
|
||||
/**
|
||||
* @deprecated
|
||||
* Use {@link #scheduleBuild(int, Cause)}. Since 1.283
|
||||
*/
|
||||
@Deprecated
|
||||
boolean scheduleBuild(int quietPeriod);
|
||||
default boolean scheduleBuild(int quietPeriod) {
|
||||
return scheduleBuild(quietPeriod, new Cause.LegacyCodeCause());
|
||||
}
|
||||
|
||||
boolean scheduleBuild(int quietPeriod, Cause c);
|
||||
}
|
||||
@@ -25,9 +25,12 @@
|
||||
package hudson.model;
|
||||
|
||||
import hudson.Functions;
|
||||
import hudson.Util;
|
||||
import jenkins.model.Jenkins;
|
||||
import jenkins.util.SystemProperties;
|
||||
import hudson.security.PermissionScope;
|
||||
import jenkins.util.io.OnMaster;
|
||||
import jline.internal.Nullable;
|
||||
import org.kohsuke.stapler.StaplerRequest;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -39,6 +42,9 @@ import hudson.security.PermissionGroup;
|
||||
import hudson.security.AccessControlled;
|
||||
import hudson.util.Secret;
|
||||
|
||||
import javax.annotation.CheckForNull;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Basic configuration unit in Hudson.
|
||||
*
|
||||
@@ -131,18 +137,32 @@ public interface Item extends PersistenceRoot, SearchableModelObject, AccessCont
|
||||
/**
|
||||
* Gets the relative name to this item from the specified group.
|
||||
*
|
||||
* @param g
|
||||
* The {@link ItemGroup} instance used as context to evaluate the relative name of this item
|
||||
* @return
|
||||
* The name of the current item, relative to p. Nested {@link ItemGroup}s are separated by {@code /} character.
|
||||
* @since 1.419
|
||||
* @return
|
||||
* String like "../foo/bar"
|
||||
* String like "../foo/bar".
|
||||
* {@code null} if one of item parents is not an {@link Item}.
|
||||
*/
|
||||
String getRelativeNameFrom(ItemGroup g);
|
||||
@Nullable
|
||||
default String getRelativeNameFrom(@CheckForNull ItemGroup g) {
|
||||
return Functions.getRelativeNameFrom(this, g);
|
||||
}
|
||||
|
||||
/**
|
||||
* Short for {@code getRelativeNameFrom(item.getParent())}
|
||||
*
|
||||
* @return String like "../foo/bar".
|
||||
* {@code null} if one of item parents is not an {@link Item}.
|
||||
* @since 1.419
|
||||
*/
|
||||
String getRelativeNameFrom(Item item);
|
||||
@Nullable
|
||||
default String getRelativeNameFrom(@Nonnull Item item) {
|
||||
return getRelativeNameFrom(item.getParent());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL of this item relative to the context root of the application.
|
||||
@@ -180,7 +200,12 @@ public interface Item extends PersistenceRoot, SearchableModelObject, AccessCont
|
||||
* (even this won't work for the same reason, which should be fixed.)
|
||||
*/
|
||||
@Deprecated
|
||||
String getAbsoluteUrl();
|
||||
default String getAbsoluteUrl() {
|
||||
String r = Jenkins.getInstance().getRootUrl();
|
||||
if(r==null)
|
||||
throw new IllegalStateException("Root URL isn't configured yet. Cannot compute absolute URL.");
|
||||
return Util.encode(r+getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Called right after when a {@link Item} is loaded from disk.
|
||||
@@ -207,7 +232,9 @@ public interface Item extends PersistenceRoot, SearchableModelObject, AccessCont
|
||||
*
|
||||
* @since 1.374
|
||||
*/
|
||||
default void onCreatedFromScratch() {}
|
||||
default void onCreatedFromScratch() {
|
||||
// do nothing by default
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the settings to a file.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package hudson.util;
|
||||
|
||||
import hudson.Functions;
|
||||
import hudson.Util;
|
||||
import hudson.os.PosixAPI;
|
||||
import hudson.os.PosixException;
|
||||
import java.nio.file.Files;
|
||||
@@ -119,13 +120,27 @@ public class IOUtils {
|
||||
|
||||
|
||||
/**
|
||||
* Gets the mode of a file/directory, if appropriate.
|
||||
* Gets the mode of a file/directory, if appropriate. Only includes read, write, and
|
||||
* execute permissions for the owner, group, and others, i.e. the max return value
|
||||
* is 0777. Consider using {@link Files#getPosixFilePermissions} instead if you only
|
||||
* care about access permissions.
|
||||
*
|
||||
* @return a file mode, or -1 if not on Unix
|
||||
* @throws PosixException if the file could not be statted, e.g. broken symlink
|
||||
*/
|
||||
public static int mode(File f) throws PosixException {
|
||||
if(Functions.isWindows()) return -1;
|
||||
return PosixAPI.jnr().stat(f.getPath()).mode();
|
||||
try {
|
||||
if (Util.NATIVE_CHMOD_MODE) {
|
||||
return PosixAPI.jnr().stat(f.getPath()).mode();
|
||||
} else {
|
||||
return Util.permissionsToMode(Files.getPosixFilePermissions(Util.fileToPath(f)));
|
||||
}
|
||||
} catch (IOException cause) {
|
||||
PosixException e = new PosixException("Unable to get file permissions", null);
|
||||
e.initCause(cause);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -377,29 +377,11 @@ public abstract class ParameterizedJobMixIn<JobT extends Job<JobT, RunT> & Param
|
||||
*/
|
||||
Map<TriggerDescriptor,Trigger<?>> getTriggers();
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #scheduleBuild(Cause)}
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
default boolean scheduleBuild() {
|
||||
return getParameterizedJobMixIn().scheduleBuild();
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean scheduleBuild(Cause c) {
|
||||
return getParameterizedJobMixIn().scheduleBuild(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #scheduleBuild(int, Cause)}
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
default boolean scheduleBuild(int quietPeriod) {
|
||||
return getParameterizedJobMixIn().scheduleBuild(quietPeriod);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean scheduleBuild(int quietPeriod, Cause c) {
|
||||
return getParameterizedJobMixIn().scheduleBuild(quietPeriod, c);
|
||||
|
||||
@@ -25,6 +25,7 @@ package hudson;
|
||||
|
||||
import hudson.FilePath.TarCompression;
|
||||
import hudson.model.TaskListener;
|
||||
import hudson.os.PosixAPI;
|
||||
import hudson.remoting.VirtualChannel;
|
||||
import hudson.util.NullStream;
|
||||
import hudson.util.StreamTaskListener;
|
||||
@@ -245,7 +246,7 @@ public class FilePathTest {
|
||||
throw x;
|
||||
}
|
||||
} finally {
|
||||
toF.chmod(700);
|
||||
toF.chmod(0700);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,6 +472,25 @@ public class FilePathTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void copyToWithPermissionSpecialPermissions() throws IOException, InterruptedException {
|
||||
assumeFalse("Test uses POSIX-specific features", Functions.isWindows());
|
||||
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("can't test on Windows", Functions.isWindows());
|
||||
|
||||
@@ -739,7 +759,38 @@ public class FilePathTest {
|
||||
// and now fail when flush is bad!
|
||||
tmpDirPath.child("../" + archive.getName()).untar(outDir, TarCompression.NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chmod() throws Exception {
|
||||
assumeFalse(Functions.isWindows());
|
||||
File f = temp.newFile("file");
|
||||
FilePath fp = new FilePath(f);
|
||||
int prevMode = fp.mode();
|
||||
assertEquals(0400, chmodAndMode(fp, 0400));
|
||||
assertEquals(0412, chmodAndMode(fp, 0412));
|
||||
assertEquals(0777, chmodAndMode(fp, 0777));
|
||||
assertEquals(prevMode, chmodAndMode(fp, prevMode));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chmodInvalidPermissions() throws Exception {
|
||||
assumeFalse(Functions.isWindows());
|
||||
File f = temp.newFolder("folder");
|
||||
FilePath fp = new FilePath(f);
|
||||
int invalidMode = 01770; // Full permissions for owner and group plus sticky bit.
|
||||
try {
|
||||
chmodAndMode(fp, invalidMode);
|
||||
fail("Setting sticky bit should fail");
|
||||
} catch (IOException e) {
|
||||
assertEquals("Invalid mode: " + invalidMode, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private int chmodAndMode(FilePath path, int mode) throws Exception {
|
||||
path.chmod(mode);
|
||||
return path.mode();
|
||||
}
|
||||
|
||||
@Test public void deleteRecursiveOnUnix() throws Exception {
|
||||
assumeFalse("Uses Unix-specific features", Functions.isWindows());
|
||||
Path targetDir = temp.newFolder("target").toPath();
|
||||
|
||||
@@ -36,6 +36,7 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.attribute.PosixFilePermissions;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
@@ -43,6 +44,7 @@ import static org.hamcrest.CoreMatchers.hasItem;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.CoreMatchers.startsWith;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
@@ -724,4 +726,41 @@ public class UtilTest {
|
||||
assertTrue(Util.isDescendant(new File(root, "."), new File(new File(root, "child"), ".")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testModeToPermissions() throws Exception {
|
||||
assertEquals(PosixFilePermissions.fromString("rwxrwxrwx"), Util.modeToPermissions(0777));
|
||||
assertEquals(PosixFilePermissions.fromString("rwxr-xrwx"), Util.modeToPermissions(0757));
|
||||
assertEquals(PosixFilePermissions.fromString("rwxr-x---"), Util.modeToPermissions(0750));
|
||||
assertEquals(PosixFilePermissions.fromString("r-xr-x---"), Util.modeToPermissions(0550));
|
||||
assertEquals(PosixFilePermissions.fromString("r-xr-----"), Util.modeToPermissions(0540));
|
||||
assertEquals(PosixFilePermissions.fromString("--xr-----"), Util.modeToPermissions(0140));
|
||||
assertEquals(PosixFilePermissions.fromString("--xr---w-"), Util.modeToPermissions(0142));
|
||||
assertEquals(PosixFilePermissions.fromString("--xr--rw-"), Util.modeToPermissions(0146));
|
||||
assertEquals(PosixFilePermissions.fromString("-wxr--rw-"), Util.modeToPermissions(0346));
|
||||
assertEquals(PosixFilePermissions.fromString("---------"), Util.modeToPermissions(0000));
|
||||
|
||||
assertEquals("Non-permission bits should be ignored", PosixFilePermissions.fromString("r-xr-----"), Util.modeToPermissions(0100540));
|
||||
|
||||
try {
|
||||
Util.modeToPermissions(01777);
|
||||
fail("Did not detect invalid mode");
|
||||
} catch (IOException e) {
|
||||
assertThat(e.getMessage(), startsWith("Invalid mode"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPermissionsToMode() throws Exception {
|
||||
assertEquals(0777, Util.permissionsToMode(PosixFilePermissions.fromString("rwxrwxrwx")));
|
||||
assertEquals(0757, Util.permissionsToMode(PosixFilePermissions.fromString("rwxr-xrwx")));
|
||||
assertEquals(0750, Util.permissionsToMode(PosixFilePermissions.fromString("rwxr-x---")));
|
||||
assertEquals(0550, Util.permissionsToMode(PosixFilePermissions.fromString("r-xr-x---")));
|
||||
assertEquals(0540, Util.permissionsToMode(PosixFilePermissions.fromString("r-xr-----")));
|
||||
assertEquals(0140, Util.permissionsToMode(PosixFilePermissions.fromString("--xr-----")));
|
||||
assertEquals(0142, Util.permissionsToMode(PosixFilePermissions.fromString("--xr---w-")));
|
||||
assertEquals(0146, Util.permissionsToMode(PosixFilePermissions.fromString("--xr--rw-")));
|
||||
assertEquals(0346, Util.permissionsToMode(PosixFilePermissions.fromString("-wxr--rw-")));
|
||||
assertEquals(0000, Util.permissionsToMode(PosixFilePermissions.fromString("---------")));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -83,9 +83,9 @@ public class TarArchiverTest {
|
||||
// extract via the tar command
|
||||
run(e, "tar", "xvpf", tar.getAbsolutePath());
|
||||
|
||||
assertEquals(0100755,e.child("a.txt").mode());
|
||||
assertEquals(0755,e.child("a.txt").mode());
|
||||
assertEquals(dirMode,e.child("subdir").mode());
|
||||
assertEquals(0100644,e.child("subdir/b.txt").mode());
|
||||
assertEquals(0644,e.child("subdir/b.txt").mode());
|
||||
|
||||
|
||||
// extract via the zip command
|
||||
@@ -93,9 +93,9 @@ public class TarArchiverTest {
|
||||
run(e, "unzip", zip.getAbsolutePath());
|
||||
e = e.listDirectories().get(0);
|
||||
|
||||
assertEquals(0100755, e.child("a.txt").mode());
|
||||
assertEquals(0755, e.child("a.txt").mode());
|
||||
assertEquals(dirMode,e.child("subdir").mode());
|
||||
assertEquals(0100644,e.child("subdir/b.txt").mode());
|
||||
assertEquals(0644,e.child("subdir/b.txt").mode());
|
||||
} finally {
|
||||
tar.delete();
|
||||
zip.delete();
|
||||
|
||||
Reference in new issue
Block a user