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   * Get the length of this file, in bytes.
104   * @return the length of this file, in bytes.
105   */
106  public long getLen() {
107    return length;
108  }
109
110  /**
111   * Is this a file?
112   * @return true if this is a file
113   */
114  public boolean isFile() {
115    return !isdir && !isSymlink();
116  }
117
118  /**
119   * Is this a directory?
120   * @return true if this is a directory
121   */
122  public boolean isDirectory() {
123    return isdir;
124  }
125  
126  /**
127   * Old interface, instead use the explicit {@link FileStatus#isFile()}, 
128   * {@link FileStatus#isDirectory()}, and {@link FileStatus#isSymlink()} 
129   * @return true if this is a directory.
130   * @deprecated Use {@link FileStatus#isFile()},  
131   * {@link FileStatus#isDirectory()}, and {@link FileStatus#isSymlink()} 
132   * instead.
133   */
134  @Deprecated
135  public boolean isDir() {
136    return isdir;
137  }
138  
139  /**
140   * Is this a symbolic link?
141   * @return true if this is a symbolic link
142   */
143  public boolean isSymlink() {
144    return symlink != null;
145  }
146
147  /**
148   * Get the block size of the file.
149   * @return the number of bytes
150   */
151  public long getBlockSize() {
152    return blocksize;
153  }
154
155  /**
156   * Get the replication factor of a file.
157   * @return the replication factor of a file.
158   */
159  public short getReplication() {
160    return block_replication;
161  }
162
163  /**
164   * Get the modification time of the file.
165   * @return the modification time of file in milliseconds since January 1, 1970 UTC.
166   */
167  public long getModificationTime() {
168    return modification_time;
169  }
170
171  /**
172   * Get the access time of the file.
173   * @return the access time of file in milliseconds since January 1, 1970 UTC.
174   */
175  public long getAccessTime() {
176    return access_time;
177  }
178
179  /**
180   * Get FsPermission associated with the file.
181   * @return permssion. If a filesystem does not have a notion of permissions
182   *         or if permissions could not be determined, then default 
183   *         permissions equivalent of "rwxrwxrwx" is returned.
184   */
185  public FsPermission getPermission() {
186    return permission;
187  }
188  
189  /**
190   * Get the owner of the file.
191   * @return owner of the file. The string could be empty if there is no
192   *         notion of owner of a file in a filesystem or if it could not 
193   *         be determined (rare).
194   */
195  public String getOwner() {
196    return owner;
197  }
198  
199  /**
200   * Get the group associated with the file.
201   * @return group for the file. The string could be empty if there is no
202   *         notion of group of a file in a filesystem or if it could not 
203   *         be determined (rare).
204   */
205  public String getGroup() {
206    return group;
207  }
208  
209  public Path getPath() {
210    return path;
211  }
212  
213  public void setPath(final Path p) {
214    path = p;
215  }
216
217  /* These are provided so that these values could be loaded lazily 
218   * by a filesystem (e.g. local file system).
219   */
220  
221  /**
222   * Sets permission.
223   * @param permission if permission is null, default value is set
224   */
225  protected void setPermission(FsPermission permission) {
226    this.permission = (permission == null) ? 
227                      FsPermission.getFileDefault() : permission;
228  }
229  
230  /**
231   * Sets owner.
232   * @param owner if it is null, default value is set
233   */  
234  protected void setOwner(String owner) {
235    this.owner = (owner == null) ? "" : owner;
236  }
237  
238  /**
239   * Sets group.
240   * @param group if it is null, default value is set
241   */  
242  protected void setGroup(String group) {
243    this.group = (group == null) ? "" :  group;
244  }
245
246  /**
247   * @return The contents of the symbolic link.
248   */
249  public Path getSymlink() throws IOException {
250    if (!isSymlink()) {
251      throw new IOException("Path " + path + " is not a symbolic link");
252    }
253    return symlink;
254  }
255
256  public void setSymlink(final Path p) {
257    symlink = p;
258  }
259  
260  //////////////////////////////////////////////////
261  // Writable
262  //////////////////////////////////////////////////
263  public void write(DataOutput out) throws IOException {
264    Text.writeString(out, getPath().toString());
265    out.writeLong(getLen());
266    out.writeBoolean(isDirectory());
267    out.writeShort(getReplication());
268    out.writeLong(getBlockSize());
269    out.writeLong(getModificationTime());
270    out.writeLong(getAccessTime());
271    getPermission().write(out);
272    Text.writeString(out, getOwner());
273    Text.writeString(out, getGroup());
274    out.writeBoolean(isSymlink());
275    if (isSymlink()) {
276      Text.writeString(out, getSymlink().toString());
277    }
278  }
279
280  public void readFields(DataInput in) throws IOException {
281    String strPath = Text.readString(in);
282    this.path = new Path(strPath);
283    this.length = in.readLong();
284    this.isdir = in.readBoolean();
285    this.block_replication = in.readShort();
286    blocksize = in.readLong();
287    modification_time = in.readLong();
288    access_time = in.readLong();
289    permission.readFields(in);
290    owner = Text.readString(in);
291    group = Text.readString(in);
292    if (in.readBoolean()) {
293      this.symlink = new Path(Text.readString(in));
294    } else {
295      this.symlink = null;
296    }
297  }
298
299  /**
300   * Compare this object to another object
301   * 
302   * @param   o the object to be compared.
303   * @return  a negative integer, zero, or a positive integer as this object
304   *   is less than, equal to, or greater than the specified object.
305   * 
306   * @throws ClassCastException if the specified object's is not of 
307   *         type FileStatus
308   */
309  public int compareTo(Object o) {
310    FileStatus other = (FileStatus)o;
311    return this.getPath().compareTo(other.getPath());
312  }
313  
314  /** Compare if this object is equal to another object
315   * @param   o the object to be compared.
316   * @return  true if two file status has the same path name; false if not.
317   */
318  public boolean equals(Object o) {
319    if (o == null) {
320      return false;
321    }
322    if (this == o) {
323      return true;
324    }
325    if (!(o instanceof FileStatus)) {
326      return false;
327    }
328    FileStatus other = (FileStatus)o;
329    return this.getPath().equals(other.getPath());
330  }
331  
332  /**
333   * Returns a hash code value for the object, which is defined as
334   * the hash code of the path name.
335   *
336   * @return  a hash code value for the path name.
337   */
338  public int hashCode() {
339    return getPath().hashCode();
340  }
341  
342  @Override
343  public String toString() {
344    StringBuilder sb = new StringBuilder();
345    sb.append(getClass().getSimpleName()); 
346    sb.append("{");
347    sb.append("path=" + path);
348    sb.append("; isDirectory=" + isdir);
349    if(!isDirectory()){
350      sb.append("; length=" + length);
351      sb.append("; replication=" + block_replication);
352      sb.append("; blocksize=" + blocksize);
353    }
354    sb.append("; modification_time=" + modification_time);
355    sb.append("; access_time=" + access_time);
356    sb.append("; owner=" + owner);
357    sb.append("; group=" + group);
358    sb.append("; permission=" + permission);
359    sb.append("; isSymlink=" + isSymlink());
360    if(isSymlink()) {
361      sb.append("; symlink=" + symlink);
362    }
363    sb.append("}");
364    return sb.toString();
365  }
366}