HDFS-10689. Hdfs dfs chmod should reset sticky bit permission when the bit is omitted in the octal mode. (Manoj Govindassamy via Lei Xu)

This commit is contained in:
Lei Xu 2016-07-28 13:52:14 -07:00
parent 67406460f0
commit a3d0cba810
3 changed files with 81 additions and 20 deletions

View File

@ -55,7 +55,7 @@ class PermissionParser {
if ((matcher = symbolic.matcher(modeStr)).find()) { if ((matcher = symbolic.matcher(modeStr)).find()) {
applyNormalPattern(modeStr, matcher); applyNormalPattern(modeStr, matcher);
} else if ((matcher = octal.matcher(modeStr)).matches()) { } else if ((matcher = octal.matcher(modeStr)).matches()) {
applyOctalPattern(modeStr, matcher); applyOctalPattern(matcher);
} else { } else {
throw new IllegalArgumentException(modeStr); throw new IllegalArgumentException(modeStr);
} }
@ -63,10 +63,10 @@ class PermissionParser {
private void applyNormalPattern(String modeStr, Matcher matcher) { private void applyNormalPattern(String modeStr, Matcher matcher) {
// Are there multiple permissions stored in one chmod? // Are there multiple permissions stored in one chmod?
boolean commaSeperated = false; boolean commaSeparated = false;
for (int i = 0; i < 1 || matcher.end() < modeStr.length(); i++) { for (int i = 0; i < 1 || matcher.end() < modeStr.length(); i++) {
if (i > 0 && (!commaSeperated || !matcher.find())) { if (i > 0 && (!commaSeparated || !matcher.find())) {
throw new IllegalArgumentException(modeStr); throw new IllegalArgumentException(modeStr);
} }
@ -144,19 +144,26 @@ class PermissionParser {
stickyBitType = type; stickyBitType = type;
} }
commaSeperated = matcher.group(4).contains(","); commaSeparated = matcher.group(4).contains(",");
} }
symbolic = true; symbolic = true;
} }
private void applyOctalPattern(String modeStr, Matcher matcher) { private void applyOctalPattern(final Matcher matcher) {
userType = groupType = othersType = '='; // Matcher groups: 1: [01] 2: [0-7]{3}
final char typeApply = '=';
stickyBitType = typeApply;
userType = typeApply;
groupType = typeApply;
othersType = typeApply;
// Check if sticky bit is specified // If sticky bit is specified get the bit, else
// default to reset for apply condition
String sb = matcher.group(1); String sb = matcher.group(1);
if (!sb.isEmpty()) { if (!sb.isEmpty()) {
stickyMode = Short.valueOf(sb.substring(0, 1)); stickyMode = Short.valueOf(sb.substring(0, 1));
stickyBitType = '='; } else {
stickyMode = 0;
} }
String str = matcher.group(2); String str = matcher.group(2);

View File

@ -17,10 +17,11 @@
*/ */
package org.apache.hadoop.fs.permission; package org.apache.hadoop.fs.permission;
import static org.apache.hadoop.fs.permission.AclEntryScope.*; import static org.apache.hadoop.fs.permission.AclEntryScope.ACCESS;
import static org.apache.hadoop.fs.permission.AclEntryType.*; import static org.apache.hadoop.fs.permission.AclEntryScope.DEFAULT;
import static org.apache.hadoop.fs.permission.FsAction.*; import static org.apache.hadoop.fs.permission.AclEntryType.USER;
import static org.apache.hadoop.hdfs.server.namenode.AclTestHelpers.*; import static org.apache.hadoop.fs.permission.FsAction.ALL;
import static org.apache.hadoop.hdfs.server.namenode.AclTestHelpers.aclEntry;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@ -46,6 +47,8 @@ import org.junit.AfterClass;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestStickyBit { public class TestStickyBit {
@ -53,6 +56,7 @@ public class TestStickyBit {
UserGroupInformation.createUserForTesting("theDoctor", new String[] {"tardis"}); UserGroupInformation.createUserForTesting("theDoctor", new String[] {"tardis"});
static final UserGroupInformation user2 = static final UserGroupInformation user2 =
UserGroupInformation.createUserForTesting("rose", new String[] {"powellestates"}); UserGroupInformation.createUserForTesting("rose", new String[] {"powellestates"});
static final Logger LOG = LoggerFactory.getLogger(TestStickyBit.class);
private static MiniDFSCluster cluster; private static MiniDFSCluster cluster;
private static Configuration conf; private static Configuration conf;
@ -344,6 +348,52 @@ public class TestStickyBit {
assertFalse(hdfs.getFileStatus(sbSetOff).getPermission().getStickyBit()); assertFalse(hdfs.getFileStatus(sbSetOff).getPermission().getStickyBit());
} }
/**
* Sticky bit set on a directory can be reset either explicitly (like 0777)
* or by omitting the bit (like 777) in the permission. Ensure that the
* directory gets its sticky bit reset whenever it is omitted in permission.
*/
@Test
public void testStickyBitReset() throws Exception {
Path sbExplicitTestDir = new Path("/DirToTestExplicitStickyBit");
Path sbOmittedTestDir = new Path("/DirToTestOmittedStickyBit");
// Creation of directories and verification of their existence
hdfs.mkdirs(sbExplicitTestDir);
hdfs.mkdirs(sbOmittedTestDir);
assertTrue(hdfs.exists(sbExplicitTestDir));
assertTrue(hdfs.exists(sbOmittedTestDir));
// Setting sticky bit explicitly on sbExplicitTestDir and verification
hdfs.setPermission(sbExplicitTestDir, new FsPermission((short) 01777));
LOG.info("Dir: {}, permission: {}", sbExplicitTestDir.getName(),
hdfs.getFileStatus(sbExplicitTestDir).getPermission());
assertTrue(hdfs.getFileStatus(sbExplicitTestDir).
getPermission().getStickyBit());
// Sticky bit omitted on sbOmittedTestDir should behave like reset
hdfs.setPermission(sbOmittedTestDir, new FsPermission((short) 0777));
LOG.info("Dir: {}, permission: {}", sbOmittedTestDir.getName(),
hdfs.getFileStatus(sbOmittedTestDir).getPermission());
assertFalse(
hdfs.getFileStatus(sbOmittedTestDir).getPermission().getStickyBit());
// Resetting sticky bit explicitly on sbExplicitTestDir and verification
hdfs.setPermission(sbExplicitTestDir, new FsPermission((short) 00777));
LOG.info("Dir: {}, permission: {}", sbExplicitTestDir.getName(),
hdfs.getFileStatus(sbExplicitTestDir).getPermission());
assertFalse(
hdfs.getFileStatus(sbExplicitTestDir).getPermission().getStickyBit());
// Set the sticky bit and reset again by omitting in the permission
hdfs.setPermission(sbOmittedTestDir, new FsPermission((short) 01777));
hdfs.setPermission(sbOmittedTestDir, new FsPermission((short) 0777));
LOG.info("Dir: {}, permission: {}", sbOmittedTestDir.getName(),
hdfs.getFileStatus(sbOmittedTestDir).getPermission());
assertFalse(
hdfs.getFileStatus(sbOmittedTestDir).getPermission().getStickyBit());
}
@Test @Test
public void testAclStickyBitPersistence() throws Exception { public void testAclStickyBitPersistence() throws Exception {
// A tale of three directories... // A tale of three directories...

View File

@ -1059,19 +1059,23 @@ public class TestDFSShell {
fs.getFileStatus(dir2).getPermission()); fs.getFileStatus(dir2).getPermission());
confirmPermissionChange("u=rwx,g=rx,o=rx", "rwxr-xr-x", fs, shell, dir2); confirmPermissionChange("u=rwx,g=rx,o=rx", "rwxr-xr-x", fs, shell, dir2);
// sticky bit explicit set
confirmPermissionChange("+t", "rwxr-xr-t", fs, shell, dir2); confirmPermissionChange("+t", "rwxr-xr-t", fs, shell, dir2);
// sticky bit explicit reset
confirmPermissionChange("-t", "rwxr-xr-x", fs, shell, dir2); confirmPermissionChange("-t", "rwxr-xr-x", fs, shell, dir2);
confirmPermissionChange("=t", "--------T", fs, shell, dir2); confirmPermissionChange("=t", "--------T", fs, shell, dir2);
// reset all permissions
confirmPermissionChange("0000", "---------", fs, shell, dir2); confirmPermissionChange("0000", "---------", fs, shell, dir2);
// turn on rw permissions for all
confirmPermissionChange("1666", "rw-rw-rwT", fs, shell, dir2); confirmPermissionChange("1666", "rw-rw-rwT", fs, shell, dir2);
// sticky bit explicit set along with x permission
confirmPermissionChange("777", "rwxrwxrwt", fs, shell, dir2); confirmPermissionChange("1777", "rwxrwxrwt", fs, shell, dir2);
// sticky bit explicit reset
confirmPermissionChange("0777", "rwxrwxrwx", fs, shell, dir2);
// sticky bit explicit set
confirmPermissionChange("1777", "rwxrwxrwt", fs, shell, dir2);
// sticky bit implicit reset
confirmPermissionChange("777", "rwxrwxrwx", fs, shell, dir2);
fs.delete(dir2, true); fs.delete(dir2, true);
} else { } else {
LOG.info("Skipped sticky bit tests on Windows"); LOG.info("Skipped sticky bit tests on Windows");