FileMode.java

  1. /*
  2.  * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
  3.  * Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org>
  4.  * and other copyright owners as documented in the project's IP log.
  5.  *
  6.  * This program and the accompanying materials are made available
  7.  * under the terms of the Eclipse Distribution License v1.0 which
  8.  * accompanies this distribution, is reproduced below, and is
  9.  * available at http://www.eclipse.org/org/documents/edl-v10.php
  10.  *
  11.  * All rights reserved.
  12.  *
  13.  * Redistribution and use in source and binary forms, with or
  14.  * without modification, are permitted provided that the following
  15.  * conditions are met:
  16.  *
  17.  * - Redistributions of source code must retain the above copyright
  18.  *   notice, this list of conditions and the following disclaimer.
  19.  *
  20.  * - Redistributions in binary form must reproduce the above
  21.  *   copyright notice, this list of conditions and the following
  22.  *   disclaimer in the documentation and/or other materials provided
  23.  *   with the distribution.
  24.  *
  25.  * - Neither the name of the Eclipse Foundation, Inc. nor the
  26.  *   names of its contributors may be used to endorse or promote
  27.  *   products derived from this software without specific prior
  28.  *   written permission.
  29.  *
  30.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  31.  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  32.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  33.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  34.  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  35.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  36.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  37.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  38.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  39.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  41.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  42.  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  43.  */

  44. package org.eclipse.jgit.lib;

  45. import java.io.IOException;
  46. import java.io.OutputStream;

  47. /**
  48.  * Constants describing various file modes recognized by GIT.
  49.  * <p>
  50.  * GIT uses a subset of the available UNIX file permission bits. The
  51.  * <code>FileMode</code> class provides access to constants defining the modes
  52.  * actually used by GIT.
  53.  * </p>
  54.  */
  55. public abstract class FileMode {
  56.     /**
  57.      * Mask to apply to a file mode to obtain its type bits.
  58.      *
  59.      * @see #TYPE_TREE
  60.      * @see #TYPE_SYMLINK
  61.      * @see #TYPE_FILE
  62.      * @see #TYPE_GITLINK
  63.      * @see #TYPE_MISSING
  64.      */
  65.     public static final int TYPE_MASK = 0170000;

  66.     /** Bit pattern for {@link #TYPE_MASK} matching {@link #TREE}. */
  67.     public static final int TYPE_TREE = 0040000;

  68.     /** Bit pattern for {@link #TYPE_MASK} matching {@link #SYMLINK}. */
  69.     public static final int TYPE_SYMLINK = 0120000;

  70.     /** Bit pattern for {@link #TYPE_MASK} matching {@link #REGULAR_FILE}. */
  71.     public static final int TYPE_FILE = 0100000;

  72.     /** Bit pattern for {@link #TYPE_MASK} matching {@link #GITLINK}. */
  73.     public static final int TYPE_GITLINK = 0160000;

  74.     /** Bit pattern for {@link #TYPE_MASK} matching {@link #MISSING}. */
  75.     public static final int TYPE_MISSING = 0000000;

  76.     /**
  77.      * Mode indicating an entry is a tree (aka directory).
  78.      */
  79.     public static final FileMode TREE = new FileMode(TYPE_TREE,
  80.             Constants.OBJ_TREE) {
  81.         @Override
  82.         @SuppressWarnings("NonOverridingEquals")
  83.         public boolean equals(int modeBits) {
  84.             return (modeBits & TYPE_MASK) == TYPE_TREE;
  85.         }
  86.     };

  87.     /** Mode indicating an entry is a symbolic link. */
  88.     public static final FileMode SYMLINK = new FileMode(TYPE_SYMLINK,
  89.             Constants.OBJ_BLOB) {
  90.         @Override
  91.         @SuppressWarnings("NonOverridingEquals")
  92.         public boolean equals(int modeBits) {
  93.             return (modeBits & TYPE_MASK) == TYPE_SYMLINK;
  94.         }
  95.     };

  96.     /** Mode indicating an entry is a non-executable file. */
  97.     public static final FileMode REGULAR_FILE = new FileMode(0100644,
  98.             Constants.OBJ_BLOB) {
  99.         @Override
  100.         @SuppressWarnings("NonOverridingEquals")
  101.         public boolean equals(int modeBits) {
  102.             return (modeBits & TYPE_MASK) == TYPE_FILE && (modeBits & 0111) == 0;
  103.         }
  104.     };

  105.     /** Mode indicating an entry is an executable file. */
  106.     public static final FileMode EXECUTABLE_FILE = new FileMode(0100755,
  107.             Constants.OBJ_BLOB) {
  108.         @Override
  109.         @SuppressWarnings("NonOverridingEquals")
  110.         public boolean equals(int modeBits) {
  111.             return (modeBits & TYPE_MASK) == TYPE_FILE && (modeBits & 0111) != 0;
  112.         }
  113.     };

  114.     /** Mode indicating an entry is a submodule commit in another repository. */
  115.     public static final FileMode GITLINK = new FileMode(TYPE_GITLINK,
  116.             Constants.OBJ_COMMIT) {
  117.         @Override
  118.         @SuppressWarnings("NonOverridingEquals")
  119.         public boolean equals(int modeBits) {
  120.             return (modeBits & TYPE_MASK) == TYPE_GITLINK;
  121.         }
  122.     };

  123.     /** Mode indicating an entry is missing during parallel walks. */
  124.     public static final FileMode MISSING = new FileMode(TYPE_MISSING,
  125.             Constants.OBJ_BAD) {
  126.         @Override
  127.         @SuppressWarnings("NonOverridingEquals")
  128.         public boolean equals(int modeBits) {
  129.             return modeBits == 0;
  130.         }
  131.     };

  132.     /**
  133.      * Convert a set of mode bits into a FileMode enumerated value.
  134.      *
  135.      * @param bits
  136.      *            the mode bits the caller has somehow obtained.
  137.      * @return the FileMode instance that represents the given bits.
  138.      */
  139.     public static final FileMode fromBits(int bits) {
  140.         switch (bits & TYPE_MASK) {
  141.         case TYPE_MISSING:
  142.             if (bits == 0)
  143.                 return MISSING;
  144.             break;
  145.         case TYPE_TREE:
  146.             return TREE;
  147.         case TYPE_FILE:
  148.             if ((bits & 0111) != 0)
  149.                 return EXECUTABLE_FILE;
  150.             return REGULAR_FILE;
  151.         case TYPE_SYMLINK:
  152.             return SYMLINK;
  153.         case TYPE_GITLINK:
  154.             return GITLINK;
  155.         }

  156.         return new FileMode(bits, Constants.OBJ_BAD) {
  157.             @Override
  158.             @SuppressWarnings("NonOverridingEquals")
  159.             public boolean equals(int a) {
  160.                 return bits == a;
  161.             }
  162.         };
  163.     }

  164.     private final byte[] octalBytes;

  165.     private final int modeBits;

  166.     private final int objectType;

  167.     private FileMode(int mode, int expType) {
  168.         modeBits = mode;
  169.         objectType = expType;
  170.         if (mode != 0) {
  171.             final byte[] tmp = new byte[10];
  172.             int p = tmp.length;

  173.             while (mode != 0) {
  174.                 tmp[--p] = (byte) ('0' + (mode & 07));
  175.                 mode >>= 3;
  176.             }

  177.             octalBytes = new byte[tmp.length - p];
  178.             for (int k = 0; k < octalBytes.length; k++) {
  179.                 octalBytes[k] = tmp[p + k];
  180.             }
  181.         } else {
  182.             octalBytes = new byte[] { '0' };
  183.         }
  184.     }

  185.     /**
  186.      * Test a file mode for equality with this
  187.      * {@link org.eclipse.jgit.lib.FileMode} object.
  188.      *
  189.      * @param modebits
  190.      *            a int.
  191.      * @return true if the mode bits represent the same mode as this object
  192.      */
  193.     @SuppressWarnings("NonOverridingEquals")
  194.     public abstract boolean equals(int modebits);

  195.     /**
  196.      * Copy this mode as a sequence of octal US-ASCII bytes.
  197.      * <p>
  198.      * The mode is copied as a sequence of octal digits using the US-ASCII
  199.      * character encoding. The sequence does not use a leading '0' prefix to
  200.      * indicate octal notation. This method is suitable for generation of a mode
  201.      * string within a GIT tree object.
  202.      * </p>
  203.      *
  204.      * @param os
  205.      *            stream to copy the mode to.
  206.      * @throws java.io.IOException
  207.      *             the stream encountered an error during the copy.
  208.      */
  209.     public void copyTo(OutputStream os) throws IOException {
  210.         os.write(octalBytes);
  211.     }

  212.     /**
  213.      * Copy this mode as a sequence of octal US-ASCII bytes.
  214.      *
  215.      * The mode is copied as a sequence of octal digits using the US-ASCII
  216.      * character encoding. The sequence does not use a leading '0' prefix to
  217.      * indicate octal notation. This method is suitable for generation of a mode
  218.      * string within a GIT tree object.
  219.      *
  220.      * @param buf
  221.      *            buffer to copy the mode to.
  222.      * @param ptr
  223.      *            position within {@code buf} for first digit.
  224.      */
  225.     public void copyTo(byte[] buf, int ptr) {
  226.         System.arraycopy(octalBytes, 0, buf, ptr, octalBytes.length);
  227.     }

  228.     /**
  229.      * Copy the number of bytes written by {@link #copyTo(OutputStream)}.
  230.      *
  231.      * @return the number of bytes written by {@link #copyTo(OutputStream)}.
  232.      */
  233.     public int copyToLength() {
  234.         return octalBytes.length;
  235.     }

  236.     /**
  237.      * Get the object type that should appear for this type of mode.
  238.      * <p>
  239.      * See the object type constants in {@link org.eclipse.jgit.lib.Constants}.
  240.      *
  241.      * @return one of the well known object type constants.
  242.      */
  243.     public int getObjectType() {
  244.         return objectType;
  245.     }

  246.     /**
  247.      * {@inheritDoc}
  248.      * <p>
  249.      * Format this mode as an octal string (for debugging only).
  250.      */
  251.     @Override
  252.     public String toString() {
  253.         return Integer.toOctalString(modeBits);
  254.     }

  255.     /**
  256.      * Get the mode bits as an integer.
  257.      *
  258.      * @return The mode bits as an integer.
  259.      */
  260.     public int getBits() {
  261.         return modeBits;
  262.     }
  263. }