blob: d7ca8f172f8e2f2eff4a4c4b0c7c88fe8ca63c17 [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.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputValidation;
import java.io.Serializable;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
import org.apache.hadoop.fs.FSProtos.FileStatusProto;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.fs.protocolPB.PBHelper;
import org.apache.hadoop.io.Writable;
/** Interface that represents the client side information for a file.
*/
@InterfaceAudience.Public
@InterfaceStability.Stable
public class FileStatus implements Writable, Comparable<Object>,
Serializable, ObjectInputValidation {
private static final long serialVersionUID = 0x13caeae8;
private Path path;
private long length;
private Boolean isdir;
private short block_replication;
private long blocksize;
private long modification_time;
private long access_time;
private FsPermission permission;
private String owner;
private String group;
private Path symlink;
private Set<AttrFlags> attr;
/**
* Flags for entity attributes.
*/
public enum AttrFlags {
/** ACL information available for this entity. */
HAS_ACL,
/** Entity is encrypted. */
HAS_CRYPT,
/** Entity is stored erasure-coded. */
HAS_EC,
/** Snapshot capability enabled. */
SNAPSHOT_ENABLED,
}
/**
* Shared, empty set of attributes (a common case for FileStatus).
*/
public static final Set<AttrFlags> NONE = Collections.<AttrFlags>emptySet();
/**
* Convert boolean attributes to a set of flags.
* @param acl See {@link AttrFlags#HAS_ACL}.
* @param crypt See {@link AttrFlags#HAS_CRYPT}.
* @param ec See {@link AttrFlags#HAS_EC}.
* @param sn See {@link AttrFlags#SNAPSHOT_ENABLED}.
* @return converted set of flags.
*/
public static Set<AttrFlags> attributes(boolean acl, boolean crypt,
boolean ec, boolean sn) {
if (!(acl || crypt || ec || sn)) {
return NONE;
}
EnumSet<AttrFlags> ret = EnumSet.noneOf(AttrFlags.class);
if (acl) {
ret.add(AttrFlags.HAS_ACL);
}
if (crypt) {
ret.add(AttrFlags.HAS_CRYPT);
}
if (ec) {
ret.add(AttrFlags.HAS_EC);
}
if (sn) {
ret.add(AttrFlags.SNAPSHOT_ENABLED);
}
return ret;
}
public FileStatus() { this(0, false, 0, 0, 0, 0, null, null, null, null); }
//We should deprecate this soon?
public FileStatus(long length, boolean isdir, int block_replication,
long blocksize, long modification_time, Path path) {
this(length, isdir, block_replication, blocksize, modification_time,
0, null, null, null, path);
}
/**
* Constructor for file systems on which symbolic links are not supported
*/
public FileStatus(long length, boolean isdir,
int block_replication,
long blocksize, long modification_time, long access_time,
FsPermission permission, String owner, String group,
Path path) {
this(length, isdir, block_replication, blocksize, modification_time,
access_time, permission, owner, group, null, path);
}
public FileStatus(long length, boolean isdir,
int block_replication,
long blocksize, long modification_time, long access_time,
FsPermission permission, String owner, String group,
Path symlink,
Path path) {
this(length, isdir, block_replication, blocksize, modification_time,
access_time, permission, owner, group, symlink, path,
false, false, false);
}
public FileStatus(long length, boolean isdir, int block_replication,
long blocksize, long modification_time, long access_time,
FsPermission permission, String owner, String group, Path symlink,
Path path, boolean hasAcl, boolean isEncrypted, boolean isErasureCoded) {
this(length, isdir, block_replication, blocksize, modification_time,
access_time, permission, owner, group, symlink, path,
attributes(hasAcl, isEncrypted, isErasureCoded, false));
}
public FileStatus(long length, boolean isdir, int block_replication,
long blocksize, long modification_time, long access_time,
FsPermission permission, String owner, String group, Path symlink,
Path path, Set<AttrFlags> attr) {
this.length = length;
this.isdir = isdir;
this.block_replication = (short)block_replication;
this.blocksize = blocksize;
this.modification_time = modification_time;
this.access_time = access_time;
if (permission != null) {
this.permission = permission;
} else if (isdir) {
this.permission = FsPermission.getDirDefault();
} else if (symlink != null) {
this.permission = FsPermission.getDefault();
} else {
this.permission = FsPermission.getFileDefault();
}
this.owner = (owner == null) ? "" : owner;
this.group = (group == null) ? "" : group;
this.symlink = symlink;
this.path = path;
this.attr = attr;
// The variables isdir and symlink indicate the type:
// 1. isdir implies directory, in which case symlink must be null.
// 2. !isdir implies a file or symlink, symlink != null implies a
// symlink, otherwise it's a file.
assert (isdir && symlink == null) || !isdir;
}
/**
* Copy constructor.
*
* @param other FileStatus to copy
*/
public FileStatus(FileStatus other) throws IOException {
// It's important to call the getters here instead of directly accessing the
// members. Subclasses like ViewFsFileStatus can override the getters.
this(other.getLen(), other.isDirectory(), other.getReplication(),
other.getBlockSize(), other.getModificationTime(), other.getAccessTime(),
other.getPermission(), other.getOwner(), other.getGroup(),
(other.isSymlink() ? other.getSymlink() : null),
other.getPath());
}
/**
* Get the length of this file, in bytes.
* @return the length of this file, in bytes.
*/
public long getLen() {
return length;
}
/**
* Is this a file?
* @return true if this is a file
*/
public boolean isFile() {
return !isDirectory() && !isSymlink();
}
/**
* Is this a directory?
* @return true if this is a directory
*/
public boolean isDirectory() {
return isdir;
}
/**
* Old interface, instead use the explicit {@link FileStatus#isFile()},
* {@link FileStatus#isDirectory()}, and {@link FileStatus#isSymlink()}
* @return true if this is a directory.
* @deprecated Use {@link FileStatus#isFile()},
* {@link FileStatus#isDirectory()}, and {@link FileStatus#isSymlink()}
* instead.
*/
@Deprecated
public final boolean isDir() {
return isDirectory();
}
/**
* Is this a symbolic link?
* @return true if this is a symbolic link
*/
public boolean isSymlink() {
return symlink != null;
}
/**
* Get the block size of the file.
* @return the number of bytes
*/
public long getBlockSize() {
return blocksize;
}
/**
* Get the replication factor of a file.
* @return the replication factor of a file.
*/
public short getReplication() {
return block_replication;
}
/**
* Get the modification time of the file.
* @return the modification time of file in milliseconds since January 1, 1970 UTC.
*/
public long getModificationTime() {
return modification_time;
}
/**
* Get the access time of the file.
* @return the access time of file in milliseconds since January 1, 1970 UTC.
*/
public long getAccessTime() {
return access_time;
}
/**
* Get FsPermission associated with the file.
* @return permission. If a filesystem does not have a notion of permissions
* or if permissions could not be determined, then default
* permissions equivalent of "rwxrwxrwx" is returned.
*/
public FsPermission getPermission() {
return permission;
}
/**
* Tell whether the underlying file or directory has ACLs set.
*
* @return true if the underlying file or directory has ACLs set.
*/
public boolean hasAcl() {
return attr.contains(AttrFlags.HAS_ACL);
}
/**
* Tell whether the underlying file or directory is encrypted or not.
*
* @return true if the underlying file is encrypted.
*/
public boolean isEncrypted() {
return attr.contains(AttrFlags.HAS_CRYPT);
}
/**
* Tell whether the underlying file or directory is erasure coded or not.
*
* @return true if the underlying file or directory is erasure coded.
*/
public boolean isErasureCoded() {
return attr.contains(AttrFlags.HAS_EC);
}
/**
* Check if directory is Snapshot enabled or not.
*
* @return true if directory is snapshot enabled
*/
public boolean isSnapshotEnabled() {
return attr.contains(AttrFlags.SNAPSHOT_ENABLED);
}
/**
* Get the owner of the file.
* @return owner of the file. The string could be empty if there is no
* notion of owner of a file in a filesystem or if it could not
* be determined (rare).
*/
public String getOwner() {
return owner;
}
/**
* Get the group associated with the file.
* @return group for the file. The string could be empty if there is no
* notion of group of a file in a filesystem or if it could not
* be determined (rare).
*/
public String getGroup() {
return group;
}
public Path getPath() {
return path;
}
public void setPath(final Path p) {
path = p;
}
/* These are provided so that these values could be loaded lazily
* by a filesystem (e.g. local file system).
*/
/**
* Sets permission.
* @param permission if permission is null, default value is set
*/
protected void setPermission(FsPermission permission) {
this.permission = (permission == null) ?
FsPermission.getFileDefault() : permission;
}
/**
* Sets owner.
* @param owner if it is null, default value is set
*/
protected void setOwner(String owner) {
this.owner = (owner == null) ? "" : owner;
}
/**
* Sets group.
* @param group if it is null, default value is set
*/
protected void setGroup(String group) {
this.group = (group == null) ? "" : group;
}
/**
* @return The contents of the symbolic link.
*/
public Path getSymlink() throws IOException {
if (!isSymlink()) {
throw new IOException("Path " + path + " is not a symbolic link");
}
return symlink;
}
public void setSymlink(final Path p) {
symlink = p;
}
/**
* Compare this FileStatus to another FileStatus
* @param o the FileStatus to be compared.
* @return a negative integer, zero, or a positive integer as this object
* is less than, equal to, or greater than the specified object.
*/
public int compareTo(FileStatus o) {
return this.getPath().compareTo(o.getPath());
}
/**
* Compare this FileStatus to another FileStatus.
* This method was added back by HADOOP-14683 to keep binary compatibility.
*
* @param o the FileStatus to be compared.
* @return a negative integer, zero, or a positive integer as this object
* is less than, equal to, or greater than the specified object.
* @throws ClassCastException if the specified object is not FileStatus
*/
@Override
public int compareTo(Object o) {
FileStatus other = (FileStatus) o;
return compareTo(other);
}
/** Compare if this object is equal to another object
* @param o the object to be compared.
* @return true if two file status has the same path name; false if not.
*/
@Override
public boolean equals(Object o) {
if (!(o instanceof FileStatus)) {
return false;
}
if (this == o) {
return true;
}
FileStatus other = (FileStatus)o;
return this.getPath().equals(other.getPath());
}
/**
* Returns a hash code value for the object, which is defined as
* the hash code of the path name.
*
* @return a hash code value for the path name.
*/
@Override
public int hashCode() {
return getPath().hashCode();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName())
.append("{")
.append("path=" + path)
.append("; isDirectory=" + isdir);
if(!isDirectory()){
sb.append("; length=" + length)
.append("; replication=" + block_replication)
.append("; blocksize=" + blocksize);
}
sb.append("; modification_time=" + modification_time)
.append("; access_time=" + access_time)
.append("; owner=" + owner)
.append("; group=" + group)
.append("; permission=" + permission)
.append("; isSymlink=" + isSymlink());
if(isSymlink()) {
try {
sb.append("; symlink=" + getSymlink());
} catch (IOException e) {
throw new RuntimeException("Unexpected exception", e);
}
}
sb.append("; hasAcl=" + hasAcl())
.append("; isEncrypted=" + isEncrypted())
.append("; isErasureCoded=" + isErasureCoded())
.append("}");
return sb.toString();
}
/**
* Read instance encoded as protobuf from stream.
* @param in Input stream
* @see PBHelper#convert(FileStatus)
* @deprecated Use the {@link PBHelper} and protobuf serialization directly.
*/
@Override
@Deprecated
public void readFields(DataInput in) throws IOException {
int size = in.readInt();
if (size < 0) {
throw new IOException("Can't read FileStatusProto with negative " +
"size of " + size);
}
byte[] buf = new byte[size];
in.readFully(buf);
FileStatusProto proto = FileStatusProto.parseFrom(buf);
FileStatus other = PBHelper.convert(proto);
isdir = other.isDirectory();
length = other.getLen();
block_replication = other.getReplication();
blocksize = other.getBlockSize();
modification_time = other.getModificationTime();
access_time = other.getAccessTime();
setPermission(other.getPermission());
setOwner(other.getOwner());
setGroup(other.getGroup());
setSymlink((other.isSymlink() ? other.getSymlink() : null));
setPath(other.getPath());
attr = attributes(other.hasAcl(), other.isEncrypted(),
other.isErasureCoded(), other.isSnapshotEnabled());
assert !(isDirectory() && isSymlink()) : "A directory cannot be a symlink";
}
/**
* Write instance encoded as protobuf to stream.
* @param out Output stream
* @see PBHelper#convert(FileStatus)
* @deprecated Use the {@link PBHelper} and protobuf serialization directly.
*/
@Override
@Deprecated
public void write(DataOutput out) throws IOException {
FileStatusProto proto = PBHelper.convert(this);
int size = proto.getSerializedSize();
out.writeInt(size);
out.write(proto.toByteArray());
}
@Override
public void validateObject() throws InvalidObjectException {
if (null == path) {
throw new InvalidObjectException("No Path in deserialized FileStatus");
}
if (null == isdir) {
throw new InvalidObjectException("No type in deserialized FileStatus");
}
}
}