/** * 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.http.server; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.fs.ContentSummary; import org.apache.hadoop.fs.FileChecksum; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.GlobFilter; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.PathFilter; import org.apache.hadoop.fs.XAttrCodec; import org.apache.hadoop.fs.XAttrSetFlag; import org.apache.hadoop.fs.http.client.HttpFSFileSystem; import org.apache.hadoop.fs.permission.AclEntry; import org.apache.hadoop.fs.permission.AclStatus; import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.hdfs.protocol.AclException; import org.apache.hadoop.io.IOUtils; import org.apache.hadoop.lib.service.FileSystemAccess; import org.apache.hadoop.util.StringUtils; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.EnumSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; /** * FileSystem operation executors used by {@link HttpFSServer}. */ @InterfaceAudience.Private public class FSOperations { /** * This class is used to group a FileStatus and an AclStatus together. * It's needed for the GETFILESTATUS and LISTSTATUS calls, which take * most info from the FileStatus and a wee bit from the AclStatus. */ private static class StatusPair { private FileStatus fileStatus; private AclStatus aclStatus; /** * Simple constructor * @param fileStatus Existing FileStatus object * @param aclStatus Existing AclStatus object */ public StatusPair(FileStatus fileStatus, AclStatus aclStatus) { this.fileStatus = fileStatus; this.aclStatus = aclStatus; } /** * Create one StatusPair by performing the underlying calls to * fs.getFileStatus and fs.getAclStatus * @param fs The FileSystem where 'path' lives * @param path The file/directory to query * @throws IOException */ public StatusPair(FileSystem fs, Path path) throws IOException { fileStatus = fs.getFileStatus(path); aclStatus = null; try { aclStatus = fs.getAclStatus(path); } catch (AclException e) { /* * The cause is almost certainly an "ACLS aren't enabled" * exception, so leave aclStatus at null and carry on. */ } catch (UnsupportedOperationException e) { /* Ditto above - this is the case for a local file system */ } } /** * Return a Map suitable for conversion into JSON format * @return The JSONish Map */ public Map<String,Object> toJson() { Map<String,Object> json = new LinkedHashMap<String,Object>(); json.put(HttpFSFileSystem.FILE_STATUS_JSON, toJsonInner(true)); return json; } /** * Return in inner part of the JSON for the status - used by both the * GETFILESTATUS and LISTSTATUS calls. * @param emptyPathSuffix Whether or not to include PATH_SUFFIX_JSON * @return The JSONish Map */ public Map<String,Object> toJsonInner(boolean emptyPathSuffix) { Map<String,Object> json = new LinkedHashMap<String,Object>(); json.put(HttpFSFileSystem.PATH_SUFFIX_JSON, (emptyPathSuffix) ? "" : fileStatus.getPath().getName()); json.put(HttpFSFileSystem.TYPE_JSON, HttpFSFileSystem.FILE_TYPE.getType(fileStatus).toString()); json.put(HttpFSFileSystem.LENGTH_JSON, fileStatus.getLen()); json.put(HttpFSFileSystem.OWNER_JSON, fileStatus.getOwner()); json.put(HttpFSFileSystem.GROUP_JSON, fileStatus.getGroup()); json.put(HttpFSFileSystem.PERMISSION_JSON, HttpFSFileSystem.permissionToString(fileStatus.getPermission())); json.put(HttpFSFileSystem.ACCESS_TIME_JSON, fileStatus.getAccessTime()); json.put(HttpFSFileSystem.MODIFICATION_TIME_JSON, fileStatus.getModificationTime()); json.put(HttpFSFileSystem.BLOCK_SIZE_JSON, fileStatus.getBlockSize()); json.put(HttpFSFileSystem.REPLICATION_JSON, fileStatus.getReplication()); if ( (aclStatus != null) && !(aclStatus.getEntries().isEmpty()) ) { json.put(HttpFSFileSystem.ACL_BIT_JSON,true); } return json; } } /** * Simple class used to contain and operate upon a list of StatusPair * objects. Used by LISTSTATUS. */ private static class StatusPairs { private StatusPair[] statusPairs; /** * Construct a list of StatusPair objects * @param fs The FileSystem where 'path' lives * @param path The directory to query * @param filter A possible filter for entries in the directory * @throws IOException */ public StatusPairs(FileSystem fs, Path path, PathFilter filter) throws IOException { /* Grab all the file statuses at once in an array */ FileStatus[] fileStatuses = fs.listStatus(path, filter); /* We'll have an array of StatusPairs of the same length */ AclStatus aclStatus = null; statusPairs = new StatusPair[fileStatuses.length]; /* * For each FileStatus, attempt to acquire an AclStatus. If the * getAclStatus throws an exception, we assume that ACLs are turned * off entirely and abandon the attempt. */ boolean useAcls = true; // Assume ACLs work until proven otherwise for (int i = 0; i < fileStatuses.length; i++) { if (useAcls) { try { aclStatus = fs.getAclStatus(fileStatuses[i].getPath()); } catch (AclException e) { /* Almost certainly due to an "ACLs not enabled" exception */ aclStatus = null; useAcls = false; } catch (UnsupportedOperationException e) { /* Ditto above - this is the case for a local file system */ aclStatus = null; useAcls = false; } } statusPairs[i] = new StatusPair(fileStatuses[i], aclStatus); } } /** * Return a Map suitable for conversion into JSON. * @return A JSONish Map */ @SuppressWarnings({"unchecked"}) public Map<String,Object> toJson() { Map<String,Object> json = new LinkedHashMap<String,Object>(); Map<String,Object> inner = new LinkedHashMap<String,Object>(); JSONArray statuses = new JSONArray(); for (StatusPair s : statusPairs) { statuses.add(s.toJsonInner(false)); } inner.put(HttpFSFileSystem.FILE_STATUS_JSON, statuses); json.put(HttpFSFileSystem.FILE_STATUSES_JSON, inner); return json; } } /** Converts an <code>AclStatus</code> object into a JSON object. * * @param aclStatus AclStatus object * * @return The JSON representation of the ACLs for the file */ @SuppressWarnings({"unchecked"}) private static Map<String,Object> aclStatusToJSON(AclStatus aclStatus) { Map<String,Object> json = new LinkedHashMap<String,Object>(); Map<String,Object> inner = new LinkedHashMap<String,Object>(); JSONArray entriesArray = new JSONArray(); inner.put(HttpFSFileSystem.OWNER_JSON, aclStatus.getOwner()); inner.put(HttpFSFileSystem.GROUP_JSON, aclStatus.getGroup()); inner.put(HttpFSFileSystem.ACL_STICKY_BIT_JSON, aclStatus.isStickyBit()); for ( AclEntry e : aclStatus.getEntries() ) { entriesArray.add(e.toString()); } inner.put(HttpFSFileSystem.ACL_ENTRIES_JSON, entriesArray); json.put(HttpFSFileSystem.ACL_STATUS_JSON, inner); return json; } /** * Converts a <code>FileChecksum</code> object into a JSON array * object. * * @param checksum file checksum. * * @return The JSON representation of the file checksum. */ @SuppressWarnings({"unchecked"}) private static Map fileChecksumToJSON(FileChecksum checksum) { Map json = new LinkedHashMap(); json.put(HttpFSFileSystem.CHECKSUM_ALGORITHM_JSON, checksum.getAlgorithmName()); json.put(HttpFSFileSystem.CHECKSUM_BYTES_JSON, org.apache.hadoop.util.StringUtils.byteToHexString(checksum.getBytes())); json.put(HttpFSFileSystem.CHECKSUM_LENGTH_JSON, checksum.getLength()); Map response = new LinkedHashMap(); response.put(HttpFSFileSystem.FILE_CHECKSUM_JSON, json); return response; } /** * Converts xAttrs to a JSON object. * * @param xAttrs file xAttrs. * @param encoding format of xattr values. * * @return The JSON representation of the xAttrs. * @throws IOException */ @SuppressWarnings({"unchecked", "rawtypes"}) private static Map xAttrsToJSON(Map<String, byte[]> xAttrs, XAttrCodec encoding) throws IOException { Map jsonMap = new LinkedHashMap(); JSONArray jsonArray = new JSONArray(); if (xAttrs != null) { for (Entry<String, byte[]> e : xAttrs.entrySet()) { Map json = new LinkedHashMap(); json.put(HttpFSFileSystem.XATTR_NAME_JSON, e.getKey()); if (e.getValue() != null) { json.put(HttpFSFileSystem.XATTR_VALUE_JSON, XAttrCodec.encodeValue(e.getValue(), encoding)); } jsonArray.add(json); } } jsonMap.put(HttpFSFileSystem.XATTRS_JSON, jsonArray); return jsonMap; } /** * Converts xAttr names to a JSON object. * * @param names file xAttr names. * * @return The JSON representation of the xAttr names. * @throws IOException */ @SuppressWarnings({"unchecked", "rawtypes"}) private static Map xAttrNamesToJSON(List<String> names) throws IOException { Map jsonMap = new LinkedHashMap(); jsonMap.put(HttpFSFileSystem.XATTRNAMES_JSON, JSONArray.toJSONString(names)); return jsonMap; } /** * Converts a <code>ContentSummary</code> object into a JSON array * object. * * @param contentSummary the content summary * * @return The JSON representation of the content summary. */ @SuppressWarnings({"unchecked"}) private static Map contentSummaryToJSON(ContentSummary contentSummary) { Map json = new LinkedHashMap(); json.put(HttpFSFileSystem.CONTENT_SUMMARY_DIRECTORY_COUNT_JSON, contentSummary.getDirectoryCount()); json.put(HttpFSFileSystem.CONTENT_SUMMARY_FILE_COUNT_JSON, contentSummary.getFileCount()); json.put(HttpFSFileSystem.CONTENT_SUMMARY_LENGTH_JSON, contentSummary.getLength()); json.put(HttpFSFileSystem.CONTENT_SUMMARY_QUOTA_JSON, contentSummary.getQuota()); json.put(HttpFSFileSystem.CONTENT_SUMMARY_SPACE_CONSUMED_JSON, contentSummary.getSpaceConsumed()); json.put(HttpFSFileSystem.CONTENT_SUMMARY_SPACE_QUOTA_JSON, contentSummary.getSpaceQuota()); Map response = new LinkedHashMap(); response.put(HttpFSFileSystem.CONTENT_SUMMARY_JSON, json); return response; } /** * Converts an object into a Json Map with with one key-value entry. * <p/> * It assumes the given value is either a JSON primitive type or a * <code>JsonAware</code> instance. * * @param name name for the key of the entry. * @param value for the value of the entry. * * @return the JSON representation of the key-value pair. */ @SuppressWarnings("unchecked") private static JSONObject toJSON(String name, Object value) { JSONObject json = new JSONObject(); json.put(name, value); return json; } /** * Executor that performs an append FileSystemAccess files system operation. */ @InterfaceAudience.Private public static class FSAppend implements FileSystemAccess.FileSystemExecutor<Void> { private InputStream is; private Path path; /** * Creates an Append executor. * * @param is input stream to append. * @param path path of the file to append. */ public FSAppend(InputStream is, String path) { this.is = is; this.path = new Path(path); } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return void. * * @throws IOException thrown if an IO error occured. */ @Override public Void execute(FileSystem fs) throws IOException { int bufferSize = fs.getConf().getInt("httpfs.buffer.size", 4096); OutputStream os = fs.append(path, bufferSize); IOUtils.copyBytes(is, os, bufferSize, true); os.close(); return null; } } /** * Executor that performs a concat FileSystemAccess files system operation. */ @InterfaceAudience.Private public static class FSConcat implements FileSystemAccess.FileSystemExecutor<Void> { private Path path; private Path[] sources; /** * Creates a Concat executor. * * @param path target path to concat to. * @param sources comma seperated absolute paths to use as sources. */ public FSConcat(String path, String[] sources) { this.sources = new Path[sources.length]; for(int i = 0; i < sources.length; i++) { this.sources[i] = new Path(sources[i]); } this.path = new Path(path); } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return void. * * @throws IOException thrown if an IO error occured. */ @Override public Void execute(FileSystem fs) throws IOException { fs.concat(path, sources); return null; } } /** * Executor that performs a truncate FileSystemAccess files system operation. */ @InterfaceAudience.Private public static class FSTruncate implements FileSystemAccess.FileSystemExecutor<JSONObject> { private Path path; private long newLength; /** * Creates a Truncate executor. * * @param path target path to truncate to. * @param newLength The size the file is to be truncated to. */ public FSTruncate(String path, long newLength) { this.path = new Path(path); this.newLength = newLength; } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return <code>true</code> if the file has been truncated to the desired, * <code>false</code> if a background process of adjusting the * length of the last block has been started, and clients should * wait for it to complete before proceeding with further file * updates. * * @throws IOException thrown if an IO error occured. */ @Override public JSONObject execute(FileSystem fs) throws IOException { boolean result = fs.truncate(path, newLength); return toJSON( StringUtils.toLowerCase(HttpFSFileSystem.TRUNCATE_JSON), result); } } /** * Executor that performs a content-summary FileSystemAccess files system operation. */ @InterfaceAudience.Private public static class FSContentSummary implements FileSystemAccess.FileSystemExecutor<Map> { private Path path; /** * Creates a content-summary executor. * * @param path the path to retrieve the content-summary. */ public FSContentSummary(String path) { this.path = new Path(path); } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return a Map object (JSON friendly) with the content-summary. * * @throws IOException thrown if an IO error occured. */ @Override public Map execute(FileSystem fs) throws IOException { ContentSummary contentSummary = fs.getContentSummary(path); return contentSummaryToJSON(contentSummary); } } /** * Executor that performs a create FileSystemAccess files system operation. */ @InterfaceAudience.Private public static class FSCreate implements FileSystemAccess.FileSystemExecutor<Void> { private InputStream is; private Path path; private short permission; private boolean override; private short replication; private long blockSize; /** * Creates a Create executor. * * @param is input stream to for the file to create. * @param path path of the file to create. * @param perm permission for the file. * @param override if the file should be overriden if it already exist. * @param repl the replication factor for the file. * @param blockSize the block size for the file. */ public FSCreate(InputStream is, String path, short perm, boolean override, short repl, long blockSize) { this.is = is; this.path = new Path(path); this.permission = perm; this.override = override; this.replication = repl; this.blockSize = blockSize; } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return The URI of the created file. * * @throws IOException thrown if an IO error occured. */ @Override public Void execute(FileSystem fs) throws IOException { if (replication == -1) { replication = fs.getDefaultReplication(path); } if (blockSize == -1) { blockSize = fs.getDefaultBlockSize(path); } FsPermission fsPermission = new FsPermission(permission); int bufferSize = fs.getConf().getInt("httpfs.buffer.size", 4096); OutputStream os = fs.create(path, fsPermission, override, bufferSize, replication, blockSize, null); IOUtils.copyBytes(is, os, bufferSize, true); os.close(); return null; } } /** * Executor that performs a delete FileSystemAccess files system operation. */ @InterfaceAudience.Private public static class FSDelete implements FileSystemAccess.FileSystemExecutor<JSONObject> { private Path path; private boolean recursive; /** * Creates a Delete executor. * * @param path path to delete. * @param recursive if the delete should be recursive or not. */ public FSDelete(String path, boolean recursive) { this.path = new Path(path); this.recursive = recursive; } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return <code>true</code> if the delete operation was successful, * <code>false</code> otherwise. * * @throws IOException thrown if an IO error occured. */ @Override public JSONObject execute(FileSystem fs) throws IOException { boolean deleted = fs.delete(path, recursive); return toJSON( StringUtils.toLowerCase(HttpFSFileSystem.DELETE_JSON), deleted); } } /** * Executor that performs a file-checksum FileSystemAccess files system operation. */ @InterfaceAudience.Private public static class FSFileChecksum implements FileSystemAccess.FileSystemExecutor<Map> { private Path path; /** * Creates a file-checksum executor. * * @param path the path to retrieve the checksum. */ public FSFileChecksum(String path) { this.path = new Path(path); } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return a Map object (JSON friendly) with the file checksum. * * @throws IOException thrown if an IO error occured. */ @Override public Map execute(FileSystem fs) throws IOException { FileChecksum checksum = fs.getFileChecksum(path); return fileChecksumToJSON(checksum); } } /** * Executor that performs a file-status FileSystemAccess files system operation. */ @InterfaceAudience.Private public static class FSFileStatus implements FileSystemAccess.FileSystemExecutor<Map> { private Path path; /** * Creates a file-status executor. * * @param path the path to retrieve the status. */ public FSFileStatus(String path) { this.path = new Path(path); } /** * Executes the filesystem getFileStatus operation and returns the * result in a JSONish Map. * * @param fs filesystem instance to use. * * @return a Map object (JSON friendly) with the file status. * * @throws IOException thrown if an IO error occurred. */ @Override public Map execute(FileSystem fs) throws IOException { StatusPair sp = new StatusPair(fs, path); return sp.toJson(); } } /** * Executor that performs a home-dir FileSystemAccess files system operation. */ @InterfaceAudience.Private public static class FSHomeDir implements FileSystemAccess.FileSystemExecutor<JSONObject> { /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return a JSON object with the user home directory. * * @throws IOException thrown if an IO error occured. */ @Override @SuppressWarnings("unchecked") public JSONObject execute(FileSystem fs) throws IOException { Path homeDir = fs.getHomeDirectory(); JSONObject json = new JSONObject(); json.put(HttpFSFileSystem.HOME_DIR_JSON, homeDir.toUri().getPath()); return json; } } /** * Executor that performs a list-status FileSystemAccess files system operation. */ @InterfaceAudience.Private public static class FSListStatus implements FileSystemAccess.FileSystemExecutor<Map>, PathFilter { private Path path; private PathFilter filter; /** * Creates a list-status executor. * * @param path the directory to retrieve the status of its contents. * @param filter glob filter to use. * * @throws IOException thrown if the filter expression is incorrect. */ public FSListStatus(String path, String filter) throws IOException { this.path = new Path(path); this.filter = (filter == null) ? this : new GlobFilter(filter); } /** * Returns data for a JSON Map containing the information for * the set of files in 'path' that match 'filter'. * * @param fs filesystem instance to use. * * @return a Map with the file status of the directory * contents that match the filter * * @throws IOException thrown if an IO error occurred. */ @Override public Map execute(FileSystem fs) throws IOException { StatusPairs sp = new StatusPairs(fs, path, filter); return sp.toJson(); } @Override public boolean accept(Path path) { return true; } } /** * Executor that performs a mkdirs FileSystemAccess files system operation. */ @InterfaceAudience.Private public static class FSMkdirs implements FileSystemAccess.FileSystemExecutor<JSONObject> { private Path path; private short permission; /** * Creates a mkdirs executor. * * @param path directory path to create. * @param permission permission to use. */ public FSMkdirs(String path, short permission) { this.path = new Path(path); this.permission = permission; } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return <code>true</code> if the mkdirs operation was successful, * <code>false</code> otherwise. * * @throws IOException thrown if an IO error occured. */ @Override public JSONObject execute(FileSystem fs) throws IOException { FsPermission fsPermission = new FsPermission(permission); boolean mkdirs = fs.mkdirs(path, fsPermission); return toJSON(HttpFSFileSystem.MKDIRS_JSON, mkdirs); } } /** * Executor that performs a open FileSystemAccess files system operation. */ @InterfaceAudience.Private public static class FSOpen implements FileSystemAccess.FileSystemExecutor<InputStream> { private Path path; /** * Creates a open executor. * * @param path file to open. */ public FSOpen(String path) { this.path = new Path(path); } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return The inputstream of the file. * * @throws IOException thrown if an IO error occured. */ @Override public InputStream execute(FileSystem fs) throws IOException { int bufferSize = HttpFSServerWebApp.get().getConfig().getInt("httpfs.buffer.size", 4096); return fs.open(path, bufferSize); } } /** * Executor that performs a rename FileSystemAccess files system operation. */ @InterfaceAudience.Private public static class FSRename implements FileSystemAccess.FileSystemExecutor<JSONObject> { private Path path; private Path toPath; /** * Creates a rename executor. * * @param path path to rename. * @param toPath new name. */ public FSRename(String path, String toPath) { this.path = new Path(path); this.toPath = new Path(toPath); } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return <code>true</code> if the rename operation was successful, * <code>false</code> otherwise. * * @throws IOException thrown if an IO error occured. */ @Override public JSONObject execute(FileSystem fs) throws IOException { boolean renamed = fs.rename(path, toPath); return toJSON(HttpFSFileSystem.RENAME_JSON, renamed); } } /** * Executor that performs a set-owner FileSystemAccess files system operation. */ @InterfaceAudience.Private public static class FSSetOwner implements FileSystemAccess.FileSystemExecutor<Void> { private Path path; private String owner; private String group; /** * Creates a set-owner executor. * * @param path the path to set the owner. * @param owner owner to set. * @param group group to set. */ public FSSetOwner(String path, String owner, String group) { this.path = new Path(path); this.owner = owner; this.group = group; } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return void. * * @throws IOException thrown if an IO error occured. */ @Override public Void execute(FileSystem fs) throws IOException { fs.setOwner(path, owner, group); return null; } } /** * Executor that performs a set-permission FileSystemAccess files system operation. */ @InterfaceAudience.Private public static class FSSetPermission implements FileSystemAccess.FileSystemExecutor<Void> { private Path path; private short permission; /** * Creates a set-permission executor. * * @param path path to set the permission. * @param permission permission to set. */ public FSSetPermission(String path, short permission) { this.path = new Path(path); this.permission = permission; } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return void. * * @throws IOException thrown if an IO error occured. */ @Override public Void execute(FileSystem fs) throws IOException { FsPermission fsPermission = new FsPermission(permission); fs.setPermission(path, fsPermission); return null; } } /** * Executor that sets the acl for a file in a FileSystem */ @InterfaceAudience.Private public static class FSSetAcl implements FileSystemAccess.FileSystemExecutor<Void> { private Path path; private List<AclEntry> aclEntries; /** * Creates a set-acl executor. * * @param path path to set the acl. * @param aclSpec acl to set. */ public FSSetAcl(String path, String aclSpec) { this.path = new Path(path); this.aclEntries = AclEntry.parseAclSpec(aclSpec, true); } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return void. * * @throws IOException thrown if an IO error occurred. */ @Override public Void execute(FileSystem fs) throws IOException { fs.setAcl(path, aclEntries); return null; } } /** * Executor that removes all acls from a file in a FileSystem */ @InterfaceAudience.Private public static class FSRemoveAcl implements FileSystemAccess.FileSystemExecutor<Void> { private Path path; /** * Creates a remove-acl executor. * * @param path path from which to remove the acl. */ public FSRemoveAcl(String path) { this.path = new Path(path); } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return void. * * @throws IOException thrown if an IO error occurred. */ @Override public Void execute(FileSystem fs) throws IOException { fs.removeAcl(path); return null; } } /** * Executor that modifies acl entries for a file in a FileSystem */ @InterfaceAudience.Private public static class FSModifyAclEntries implements FileSystemAccess.FileSystemExecutor<Void> { private Path path; private List<AclEntry> aclEntries; /** * Creates a modify-acl executor. * * @param path path to set the acl. * @param aclSpec acl to set. */ public FSModifyAclEntries(String path, String aclSpec) { this.path = new Path(path); this.aclEntries = AclEntry.parseAclSpec(aclSpec, true); } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return void. * * @throws IOException thrown if an IO error occurred. */ @Override public Void execute(FileSystem fs) throws IOException { fs.modifyAclEntries(path, aclEntries); return null; } } /** * Executor that removes acl entries from a file in a FileSystem */ @InterfaceAudience.Private public static class FSRemoveAclEntries implements FileSystemAccess.FileSystemExecutor<Void> { private Path path; private List<AclEntry> aclEntries; /** * Creates a remove acl entry executor. * * @param path path to set the acl. * @param aclSpec acl parts to remove. */ public FSRemoveAclEntries(String path, String aclSpec) { this.path = new Path(path); this.aclEntries = AclEntry.parseAclSpec(aclSpec, true); } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return void. * * @throws IOException thrown if an IO error occurred. */ @Override public Void execute(FileSystem fs) throws IOException { fs.removeAclEntries(path, aclEntries); return null; } } /** * Executor that removes the default acl from a directory in a FileSystem */ @InterfaceAudience.Private public static class FSRemoveDefaultAcl implements FileSystemAccess.FileSystemExecutor<Void> { private Path path; /** * Creates an executor for removing the default acl. * * @param path path to set the acl. */ public FSRemoveDefaultAcl(String path) { this.path = new Path(path); } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return void. * * @throws IOException thrown if an IO error occurred. */ @Override public Void execute(FileSystem fs) throws IOException { fs.removeDefaultAcl(path); return null; } } /** * Executor that gets the ACL information for a given file. */ @InterfaceAudience.Private public static class FSAclStatus implements FileSystemAccess.FileSystemExecutor<Map> { private Path path; /** * Creates an executor for getting the ACLs for a file. * * @param path the path to retrieve the ACLs. */ public FSAclStatus(String path) { this.path = new Path(path); } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return a Map object (JSON friendly) with the file status. * * @throws IOException thrown if an IO error occurred. */ @Override public Map execute(FileSystem fs) throws IOException { AclStatus status = fs.getAclStatus(path); return aclStatusToJSON(status); } } /** * Executor that performs a set-replication FileSystemAccess files system operation. */ @InterfaceAudience.Private public static class FSSetReplication implements FileSystemAccess.FileSystemExecutor<JSONObject> { private Path path; private short replication; /** * Creates a set-replication executor. * * @param path path to set the replication factor. * @param replication replication factor to set. */ public FSSetReplication(String path, short replication) { this.path = new Path(path); this.replication = replication; } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return <code>true</code> if the replication value was set, * <code>false</code> otherwise. * * @throws IOException thrown if an IO error occured. */ @Override @SuppressWarnings("unchecked") public JSONObject execute(FileSystem fs) throws IOException { boolean ret = fs.setReplication(path, replication); JSONObject json = new JSONObject(); json.put(HttpFSFileSystem.SET_REPLICATION_JSON, ret); return json; } } /** * Executor that performs a set-times FileSystemAccess files system operation. */ @InterfaceAudience.Private public static class FSSetTimes implements FileSystemAccess.FileSystemExecutor<Void> { private Path path; private long mTime; private long aTime; /** * Creates a set-times executor. * * @param path path to set the times. * @param mTime modified time to set. * @param aTime access time to set. */ public FSSetTimes(String path, long mTime, long aTime) { this.path = new Path(path); this.mTime = mTime; this.aTime = aTime; } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return void. * * @throws IOException thrown if an IO error occured. */ @Override public Void execute(FileSystem fs) throws IOException { fs.setTimes(path, mTime, aTime); return null; } } /** * Executor that performs a setxattr FileSystemAccess files system operation. */ @InterfaceAudience.Private public static class FSSetXAttr implements FileSystemAccess.FileSystemExecutor<Void> { private Path path; private String name; private byte[] value; private EnumSet<XAttrSetFlag> flag; public FSSetXAttr(String path, String name, String encodedValue, EnumSet<XAttrSetFlag> flag) throws IOException { this.path = new Path(path); this.name = name; this.value = XAttrCodec.decodeValue(encodedValue); this.flag = flag; } @Override public Void execute(FileSystem fs) throws IOException { fs.setXAttr(path, name, value, flag); return null; } } /** * Executor that performs a removexattr FileSystemAccess files system * operation. */ @InterfaceAudience.Private public static class FSRemoveXAttr implements FileSystemAccess.FileSystemExecutor<Void> { private Path path; private String name; public FSRemoveXAttr(String path, String name) { this.path = new Path(path); this.name = name; } @Override public Void execute(FileSystem fs) throws IOException { fs.removeXAttr(path, name); return null; } } /** * Executor that performs listing xattrs FileSystemAccess files system * operation. */ @SuppressWarnings("rawtypes") @InterfaceAudience.Private public static class FSListXAttrs implements FileSystemAccess.FileSystemExecutor<Map> { private Path path; /** * Creates listing xattrs executor. * * @param path the path to retrieve the xattrs. */ public FSListXAttrs(String path) { this.path = new Path(path); } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return Map a map object (JSON friendly) with the xattr names. * * @throws IOException thrown if an IO error occured. */ @Override public Map execute(FileSystem fs) throws IOException { List<String> names = fs.listXAttrs(path); return xAttrNamesToJSON(names); } } /** * Executor that performs getting xattrs FileSystemAccess files system * operation. */ @SuppressWarnings("rawtypes") @InterfaceAudience.Private public static class FSGetXAttrs implements FileSystemAccess.FileSystemExecutor<Map> { private Path path; private List<String> names; private XAttrCodec encoding; /** * Creates getting xattrs executor. * * @param path the path to retrieve the xattrs. */ public FSGetXAttrs(String path, List<String> names, XAttrCodec encoding) { this.path = new Path(path); this.names = names; this.encoding = encoding; } /** * Executes the filesystem operation. * * @param fs filesystem instance to use. * * @return Map a map object (JSON friendly) with the xattrs. * * @throws IOException thrown if an IO error occured. */ @Override public Map execute(FileSystem fs) throws IOException { Map<String, byte[]> xattrs = null; if (names != null && !names.isEmpty()) { xattrs = fs.getXAttrs(path, names); } else { xattrs = fs.getXAttrs(path); } return xAttrsToJSON(xattrs, encoding); } } }