|
@@ -23,6 +23,7 @@ import java.util.regex.Pattern;
|
|
|
|
|
|
import org.apache.hadoop.fs.FsShell.CmdHandler;
|
|
|
import org.apache.hadoop.fs.permission.FsPermission;
|
|
|
+import org.apache.hadoop.fs.permission.ChmodParser;
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -39,168 +40,33 @@ class FsShellPermissions {
|
|
|
* also enforce octal mode specifications of either 3 digits without a sticky
|
|
|
* bit setting or four digits with a sticky bit setting.
|
|
|
*/
|
|
|
- private static Pattern chmodNormalPattern =
|
|
|
- Pattern.compile("\\G\\s*([ugoa]*)([+=-]+)([rwxXt]+)([,\\s]*)\\s*");
|
|
|
- private static Pattern chmodOctalPattern =
|
|
|
- Pattern.compile("^\\s*[+]?([01]?)([0-7]{3})\\s*$");
|
|
|
|
|
|
static String CHMOD_USAGE =
|
|
|
"-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...";
|
|
|
|
|
|
+ private static ChmodParser pp;
|
|
|
+
|
|
|
private static class ChmodHandler extends CmdHandler {
|
|
|
|
|
|
- private short userMode;
|
|
|
- private short groupMode;
|
|
|
- private short othersMode;
|
|
|
- private short stickyMode;
|
|
|
- private char userType = '+';
|
|
|
- private char groupType = '+';
|
|
|
- private char othersType = '+';
|
|
|
- private char stickyBitType = '+';
|
|
|
-
|
|
|
- private void applyNormalPattern(String modeStr, Matcher matcher)
|
|
|
- throws IOException {
|
|
|
- // Are there multiple permissions stored in one chmod?
|
|
|
- boolean commaSeperated = false;
|
|
|
-
|
|
|
- for(int i=0; i < 1 || matcher.end() < modeStr.length(); i++) {
|
|
|
- if (i>0 && (!commaSeperated || !matcher.find())) {
|
|
|
- patternError(modeStr);
|
|
|
- }
|
|
|
-
|
|
|
- /* groups : 1 : [ugoa]*
|
|
|
- * 2 : [+-=]
|
|
|
- * 3 : [rwxXt]+
|
|
|
- * 4 : [,\s]*
|
|
|
- */
|
|
|
-
|
|
|
- String str = matcher.group(2);
|
|
|
- char type = str.charAt(str.length() - 1);
|
|
|
-
|
|
|
- boolean user, group, others, stickyBit;
|
|
|
- user = group = others = stickyBit = false;
|
|
|
-
|
|
|
- for(char c : matcher.group(1).toCharArray()) {
|
|
|
- switch (c) {
|
|
|
- case 'u' : user = true; break;
|
|
|
- case 'g' : group = true; break;
|
|
|
- case 'o' : others = true; break;
|
|
|
- case 'a' : break;
|
|
|
- default : throw new RuntimeException("Unexpected");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (!(user || group || others)) { // same as specifying 'a'
|
|
|
- user = group = others = true;
|
|
|
- }
|
|
|
-
|
|
|
- short mode = 0;
|
|
|
-
|
|
|
- for(char c : matcher.group(3).toCharArray()) {
|
|
|
- switch (c) {
|
|
|
- case 'r' : mode |= 4; break;
|
|
|
- case 'w' : mode |= 2; break;
|
|
|
- case 'x' : mode |= 1; break;
|
|
|
- case 'X' : mode |= 8; break;
|
|
|
- case 't' : stickyBit = true; break;
|
|
|
- default : throw new RuntimeException("Unexpected");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if ( user ) {
|
|
|
- userMode = mode;
|
|
|
- userType = type;
|
|
|
- }
|
|
|
-
|
|
|
- if ( group ) {
|
|
|
- groupMode = mode;
|
|
|
- groupType = type;
|
|
|
- }
|
|
|
-
|
|
|
- if ( others ) {
|
|
|
- othersMode = mode;
|
|
|
- othersType = type;
|
|
|
-
|
|
|
- stickyMode = (short) (stickyBit ? 1 : 0);
|
|
|
- stickyBitType = type;
|
|
|
- }
|
|
|
-
|
|
|
- commaSeperated = matcher.group(4).contains(",");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void applyOctalPattern(String modeStr, Matcher matcher) {
|
|
|
- userType = groupType = othersType = '=';
|
|
|
-
|
|
|
- // Check if sticky bit is specified
|
|
|
- String sb = matcher.group(1);
|
|
|
- if(!sb.isEmpty()) {
|
|
|
- stickyMode = Short.valueOf(sb.substring(0, 1));
|
|
|
- stickyBitType = '=';
|
|
|
- }
|
|
|
-
|
|
|
- String str = matcher.group(2);
|
|
|
- userMode = Short.valueOf(str.substring(0, 1));
|
|
|
- groupMode = Short.valueOf(str.substring(1, 2));
|
|
|
- othersMode = Short.valueOf(str.substring(2, 3));
|
|
|
- }
|
|
|
-
|
|
|
- private void patternError(String mode) throws IOException {
|
|
|
- throw new IOException("chmod : mode '" + mode +
|
|
|
- "' does not match the expected pattern.");
|
|
|
- }
|
|
|
-
|
|
|
ChmodHandler(FileSystem fs, String modeStr) throws IOException {
|
|
|
super("chmod", fs);
|
|
|
- Matcher matcher = null;
|
|
|
-
|
|
|
- if ((matcher = chmodNormalPattern.matcher(modeStr)).find()) {
|
|
|
- applyNormalPattern(modeStr, matcher);
|
|
|
- } else if ((matcher = chmodOctalPattern.matcher(modeStr)).matches()) {
|
|
|
- applyOctalPattern(modeStr, matcher);
|
|
|
- } else {
|
|
|
- patternError(modeStr);
|
|
|
+ try {
|
|
|
+ pp = new ChmodParser(modeStr);
|
|
|
+ } catch(IllegalArgumentException iea) {
|
|
|
+ patternError(iea.getMessage());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private int applyChmod(char type, int mode, int existing, boolean exeOk) {
|
|
|
- boolean capX = false;
|
|
|
-
|
|
|
- if ((mode&8) != 0) { // convert X to x;
|
|
|
- capX = true;
|
|
|
- mode &= ~8;
|
|
|
- mode |= 1;
|
|
|
- }
|
|
|
-
|
|
|
- switch (type) {
|
|
|
- case '+' : mode = mode | existing; break;
|
|
|
- case '-' : mode = (~mode) & existing; break;
|
|
|
- case '=' : break;
|
|
|
- default : throw new RuntimeException("Unexpected");
|
|
|
- }
|
|
|
-
|
|
|
- // if X is specified add 'x' only if exeOk or x was already set.
|
|
|
- if (capX && !exeOk && (mode&1) != 0 && (existing&1) == 0) {
|
|
|
- mode &= ~1; // remove x
|
|
|
- }
|
|
|
-
|
|
|
- return mode;
|
|
|
+ private void patternError(String mode) throws IOException {
|
|
|
+ throw new IOException("chmod : mode '" + mode +
|
|
|
+ "' does not match the expected pattern.");
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
@Override
|
|
|
public void run(FileStatus file, FileSystem srcFs) throws IOException {
|
|
|
- FsPermission perms = file.getPermission();
|
|
|
- int existing = perms.toShort();
|
|
|
- boolean exeOk = file.isDir() || (existing & 0111) != 0;
|
|
|
- int newperms = ( applyChmod(stickyBitType, stickyMode,
|
|
|
- (existing>>>9), false) << 9 |
|
|
|
- applyChmod(userType, userMode,
|
|
|
- (existing>>>6)&7, exeOk) << 6 |
|
|
|
- applyChmod(groupType, groupMode,
|
|
|
- (existing>>>3)&7, exeOk) << 3 |
|
|
|
- applyChmod(othersType, othersMode, existing&7, exeOk));
|
|
|
+ int newperms = pp.applyNewPermission(file);
|
|
|
|
|
|
- if (existing != newperms) {
|
|
|
+ if (file.getPermission().toShort() != newperms) {
|
|
|
try {
|
|
|
srcFs.setPermission(file.getPath(),
|
|
|
new FsPermission((short)newperms));
|