001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.fs;
019
020import java.io.DataInput;
021import java.io.DataOutput;
022import java.io.IOException;
023
024import org.apache.hadoop.classification.InterfaceAudience;
025import org.apache.hadoop.classification.InterfaceStability;
026import org.apache.hadoop.fs.permission.FsPermission;
027import org.apache.hadoop.io.Text;
028import org.apache.hadoop.io.Writable;
029
030/** Interface that represents the client side information for a file.
031 */
032@InterfaceAudience.Public
033@InterfaceStability.Stable
034public class FileStatus implements Writable, Comparable {
035
036  private Path path;
037  private long length;
038  private boolean isdir;
039  private short block_replication;
040  private long blocksize;
041  private long modification_time;
042  private long access_time;
043  private FsPermission permission;
044  private String owner;
045  private String group;
046  private Path symlink;
047  
048  public FileStatus() { this(0, false, 0, 0, 0, 0, null, null, null, null); }
049  
050  //We should deprecate this soon?
051  public FileStatus(long length, boolean isdir, int block_replication,
052                    long blocksize, long modification_time, Path path) {
053
054    this(length, isdir, block_replication, blocksize, modification_time,
055         0, null, null, null, path);
056  }
057
058  /**
059   * Constructor for file systems on which symbolic links are not supported
060   */
061  public FileStatus(long length, boolean isdir,
062                    int block_replication,
063                    long blocksize, long modification_time, long access_time,
064                    FsPermission permission, String owner, String group, 
065                    Path path) {
066    this(length, isdir, block_replication, blocksize, modification_time,
067         access_time, permission, owner, group, null, path);
068  }
069
070  public FileStatus(long length, boolean isdir,
071                    int block_replication,
072                    long blocksize, long modification_time, long access_time,
073                    FsPermission permission, String owner, String group, 
074                    Path symlink,
075                    Path path) {
076    this.length = length;
077    this.isdir = isdir;
078    this.block_replication = (short)block_replication;
079    this.blocksize = blocksize;
080    this.modification_time = modification_time;
081    this.access_time = access_time;
082    if (permission != null) {
083      this.permission = permission;
084    } else if (isdir) {
085      this.permission = FsPermission.getDirDefault();
086    } else if (symlink!=null) {
087      this.permission = FsPermission.getDefault();
088    } else {
089      this.permission = FsPermission.getFileDefault();
090    }
091    this.owner = (owner == null) ? "" : owner;
092    this.group = (group == null) ? "" : group;
093    this.symlink = symlink;
094    this.path = path;
095    // The variables isdir and symlink indicate the type:
096    // 1. isdir implies directory, in which case symlink must be null.
097    // 2. !isdir implies a file or symlink, symlink != null implies a
098    //    symlink, otherwise it's a file.
099    assert (isdir && symlink == null) || !isdir;
100  }
101
102  /**
103   * Copy constructor.
104   *
105   * @param other FileStatus to copy
106   */
107  public FileStatus(FileStatus other) throws IOException {
108    // It's important to call the getters here instead of directly accessing the
109    // members.  Subclasses like ViewFsFileStatus can override the getters.
110    this(other.getLen(), other.isDirectory(), other.getReplication(),
111      other.getBlockSize(), other.getModificationTime(), other.getAccessTime(),
112      other.getPermission(), other.getOwner(), other.getGroup(),
113      (other.isSymlink() ? other.getSymlink() : null),
114      other.getPath());
115  }
116
117  /**
118   * Get the length of this file, in bytes.
119   * @return the length of this file, in bytes.
120   */
121  public long getLen() {
122    return length;
123  }
124
125  /**
126   * Is this a file?
127   * @return true if this is a file
128   */
129  public boolean isFile() {
130    return !isdir && !isSymlink();
131  }
132
133  /**
134   * Is this a directory?
135   * @return true if this is a directory
136   */
137  public boolean isDirectory() {
138    return isdir;
139  }
140  
141  /**
142   * Old interface, instead use the explicit {@link FileStatus#isFile()}, 
143   * {@link FileStatus#isDirectory()}, and {@link FileStatus#isSymlink()} 
144   * @return true if this is a directory.
145   * @deprecated Use {@link FileStatus#isFile()},  
146   * {@link FileStatus#isDirectory()}, and {@link FileStatus#isSymlink()} 
147   * instead.
148   */
149  @Deprecated
150  public boolean isDir() {
151    return isdir;
152  }
153  
154  /**
155   * Is this a table type
156   * @return true if this is a table object, it cannot be a diretory.
157   */
158  public boolean isTable() {
159    return false;
160  }
161
162  /**
163   * Is this a symbolic link?
164   * @return true if this is a symbolic link
165   */
166  public boolean isSymlink() {
167    return symlink != null;
168  }
169
170  /**
171   * Get the block size of the file.
172   * @return the number of bytes
173   */
174  public long getBlockSize() {
175    return blocksize;
176  }
177
178  /**
179   * Get the replication factor of a file.
180   * @return the replication factor of a file.
181   */
182  public short getReplication() {
183    return block_replication;
184  }
185
186  /**
187   * Get the modification time of the file.
188   * @return the modification time of file in milliseconds since January 1, 1970 UTC.
189   */
190  public long getModificationTime() {
191    return modification_time;
192  }
193
194  /**
195   * Get the access time of the file.
196   * @return the access time of file in milliseconds since January 1, 1970 UTC.
197   */
198  public long getAccessTime() {
199    return access_time;
200  }
201
202  /**
203   * Get FsPermission associated with the file.
204   * @return permssion. If a filesystem does not have a notion of permissions
205   *         or if permissions could not be determined, then default 
206   *         permissions equivalent of "rwxrwxrwx" is returned.
207   */
208  public FsPermission getPermission() {
209    return permission;
210  }
211
212  /**
213   * Tell whether the underlying file or directory is encrypted or not.
214   *
215   * @return true if the underlying file is encrypted.
216   */
217  public boolean isEncrypted() {
218    return permission.getEncryptedBit();
219  }
220  
221  /**
222   * Get the owner of the file.
223   * @return owner of the file. The string could be empty if there is no
224   *         notion of owner of a file in a filesystem or if it could not 
225   *         be determined (rare).
226   */
227  public String getOwner() {
228    return owner;
229  }
230  
231  /**
232   * Get the group associated with the file.
233   * @return group for the file. The string could be empty if there is no
234   *         notion of group of a file in a filesystem or if it could not 
235   *         be determined (rare).
236   */
237  public String getGroup() {
238    return group;
239  }
240  
241  public Path getPath() {
242    return path;
243  }
244  
245  public void setPath(final Path p) {
246    path = p;
247  }
248
249  /* These are provided so that these values could be loaded lazily 
250   * by a filesystem (e.g. local file system).
251   */
252  
253  /**
254   * Sets permission.
255   * @param permission if permission is null, default value is set
256   */
257  protected void setPermission(FsPermission permission) {
258    this.permission = (permission == null) ? 
259                      FsPermission.getFileDefault() : permission;
260  }
261  
262  /**
263   * Sets owner.
264   * @param owner if it is null, default value is set
265   */  
266  protected void setOwner(String owner) {
267    this.owner = (owner == null) ? "" : owner;
268  }
269  
270  /**
271   * Sets group.
272   * @param group if it is null, default value is set
273   */  
274  protected void setGroup(String group) {
275    this.group = (group == null) ? "" :  group;
276  }
277
278  /**
279   * @return The contents of the symbolic link.
280   */
281  public Path getSymlink() throws IOException {
282    if (!isSymlink()) {
283      throw new IOException("Path " + path + " is not a symbolic link");
284    }
285    return symlink;
286  }
287
288  public void setSymlink(final Path p) {
289    symlink = p;
290  }
291  
292  //////////////////////////////////////////////////
293  // Writable
294  //////////////////////////////////////////////////
295  @Override
296  public void write(DataOutput out) throws IOException {
297    Text.writeString(out, getPath().toString(), Text.DEFAULT_MAX_LEN);
298    out.writeLong(getLen());
299    out.writeBoolean(isDirectory());
300    out.writeShort(getReplication());
301    out.writeLong(getBlockSize());
302    out.writeLong(getModificationTime());
303    out.writeLong(getAccessTime());
304    getPermission().write(out);
305    Text.writeString(out, getOwner(), Text.DEFAULT_MAX_LEN);
306    Text.writeString(out, getGroup(), Text.DEFAULT_MAX_LEN);
307    out.writeBoolean(isSymlink());
308    if (isSymlink()) {
309      Text.writeString(out, getSymlink().toString(), Text.DEFAULT_MAX_LEN);
310    }
311  }
312
313  @Override
314  public void readFields(DataInput in) throws IOException {
315    String strPath = Text.readString(in, Text.DEFAULT_MAX_LEN);
316    this.path = new Path(strPath);
317    this.length = in.readLong();
318    this.isdir = in.readBoolean();
319    this.block_replication = in.readShort();
320    blocksize = in.readLong();
321    modification_time = in.readLong();
322    access_time = in.readLong();
323    permission.readFields(in);
324    owner = Text.readString(in, Text.DEFAULT_MAX_LEN);
325    group = Text.readString(in, Text.DEFAULT_MAX_LEN);
326    if (in.readBoolean()) {
327      this.symlink = new Path(Text.readString(in, Text.DEFAULT_MAX_LEN));
328    } else {
329      this.symlink = null;
330    }
331  }
332
333  /**
334   * Compare this object to another object
335   * 
336   * @param   o the object to be compared.
337   * @return  a negative integer, zero, or a positive integer as this object
338   *   is less than, equal to, or greater than the specified object.
339   * 
340   * @throws ClassCastException if the specified object's is not of 
341   *         type FileStatus
342   */
343  @Override
344  public int compareTo(Object o) {
345    FileStatus other = (FileStatus)o;
346    return this.getPath().compareTo(other.getPath());
347  }
348  
349  /** Compare if this object is equal to another object
350   * @param   o the object to be compared.
351   * @return  true if two file status has the same path name; false if not.
352   */
353  @Override
354  public boolean equals(Object o) {
355    if (o == null) {
356      return false;
357    }
358    if (this == o) {
359      return true;
360    }
361    if (!(o instanceof FileStatus)) {
362      return false;
363    }
364    FileStatus other = (FileStatus)o;
365    return this.getPath().equals(other.getPath());
366  }
367  
368  /**
369   * Returns a hash code value for the object, which is defined as
370   * the hash code of the path name.
371   *
372   * @return  a hash code value for the path name.
373   */
374  @Override
375  public int hashCode() {
376    return getPath().hashCode();
377  }
378  
379  @Override
380  public String toString() {
381    StringBuilder sb = new StringBuilder();
382    sb.append(getClass().getSimpleName()); 
383    sb.append("{");
384    sb.append("path=" + path);
385    sb.append("; isDirectory=" + isdir);
386    if(!isDirectory()){
387      sb.append("; length=" + length);
388      sb.append("; replication=" + block_replication);
389      sb.append("; blocksize=" + blocksize);
390    }
391    sb.append("; modification_time=" + modification_time);
392    sb.append("; access_time=" + access_time);
393    sb.append("; owner=" + owner);
394    sb.append("; group=" + group);
395    sb.append("; permission=" + permission);
396    sb.append("; isSymlink=" + isSymlink());
397    if(isSymlink()) {
398      sb.append("; symlink=" + symlink);
399    }
400    sb.append("}");
401    return sb.toString();
402  }
403}