blob: a3466568d6294f4b8ed8c7cfea7b8f20eda884ed [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.fs;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.fs.FsShell.CmdHandler;
import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.fs.permission.ChmodParser;
/**
* This class is the home for file permissions related commands.
* Moved to this separate class since FsShell is getting too large.
*/
@InterfaceAudience.Private
@InterfaceStability.Unstable
class FsShellPermissions {
/*========== chmod ==========*/
/*
* The pattern is almost as flexible as mode allowed by chmod shell command.
* The main restriction is that we recognize only rwxXt. To reduce errors we
* also enforce octal mode specifications of either 3 digits without a sticky
* bit setting or four digits with a sticky bit setting.
*/
static String CHMOD_USAGE =
"-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...";
private static ChmodParser pp;
private static class ChmodHandler extends CmdHandler {
ChmodHandler(FileSystem fs, String modeStr) throws IOException {
super("chmod", fs);
try {
pp = new ChmodParser(modeStr);
} catch(IllegalArgumentException iea) {
patternError(iea.getMessage());
}
}
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 {
int newperms = pp.applyNewPermission(file);
if (file.getPermission().toShort() != newperms) {
try {
srcFs.setPermission(file.getPath(),
new FsPermission((short)newperms));
} catch (IOException e) {
System.err.println(getName() + ": changing permissions of '" +
file.getPath() + "':" + e.getMessage());
}
}
}
}
/*========== chown ==========*/
static private String allowedChars = "[-_./@a-zA-Z0-9]";
///allows only "allowedChars" above in names for owner and group
static private Pattern chownPattern =
Pattern.compile("^\\s*(" + allowedChars + "+)?" +
"([:](" + allowedChars + "*))?\\s*$");
static private Pattern chgrpPattern =
Pattern.compile("^\\s*(" + allowedChars + "+)\\s*$");
static String CHOWN_USAGE = "-chown [-R] [OWNER][:[GROUP]] PATH...";
static String CHGRP_USAGE = "-chgrp [-R] GROUP PATH...";
private static class ChownHandler extends CmdHandler {
protected String owner = null;
protected String group = null;
protected ChownHandler(String cmd, FileSystem fs) { //for chgrp
super(cmd, fs);
}
ChownHandler(FileSystem fs, String ownerStr) throws IOException {
super("chown", fs);
Matcher matcher = chownPattern.matcher(ownerStr);
if (!matcher.matches()) {
throw new IOException("'" + ownerStr + "' does not match " +
"expected pattern for [owner][:group].");
}
owner = matcher.group(1);
group = matcher.group(3);
if (group != null && group.length() == 0) {
group = null;
}
if (owner == null && group == null) {
throw new IOException("'" + ownerStr + "' does not specify " +
" onwer or group.");
}
}
@Override
public void run(FileStatus file, FileSystem srcFs) throws IOException {
//Should we do case insensitive match?
String newOwner = (owner == null || owner.equals(file.getOwner())) ?
null : owner;
String newGroup = (group == null || group.equals(file.getGroup())) ?
null : group;
if (newOwner != null || newGroup != null) {
try {
srcFs.setOwner(file.getPath(), newOwner, newGroup);
} catch (IOException e) {
System.err.println(getName() + ": changing ownership of '" +
file.getPath() + "':" + e.getMessage());
}
}
}
}
/*========== chgrp ==========*/
private static class ChgrpHandler extends ChownHandler {
ChgrpHandler(FileSystem fs, String groupStr) throws IOException {
super("chgrp", fs);
Matcher matcher = chgrpPattern.matcher(groupStr);
if (!matcher.matches()) {
throw new IOException("'" + groupStr + "' does not match " +
"expected pattern for group");
}
group = matcher.group(1);
}
}
static int changePermissions(FileSystem fs, String cmd,
String argv[], int startIndex, FsShell shell)
throws IOException {
CmdHandler handler = null;
boolean recursive = false;
// handle common arguments, currently only "-R"
for (; startIndex < argv.length && argv[startIndex].equals("-R");
startIndex++) {
recursive = true;
}
if ( startIndex >= argv.length ) {
throw new IOException("Not enough arguments for the command");
}
if (cmd.equals("-chmod")) {
handler = new ChmodHandler(fs, argv[startIndex++]);
} else if (cmd.equals("-chown")) {
handler = new ChownHandler(fs, argv[startIndex++]);
} else if (cmd.equals("-chgrp")) {
handler = new ChgrpHandler(fs, argv[startIndex++]);
}
return shell.runCmdHandler(handler, argv, startIndex, recursive);
}
}