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 45 package org.eclipse.jgit.lib; 46 47 import java.io.IOException; 48 import java.io.OutputStream; 49 50 /** 51 * Constants describing various file modes recognized by GIT. 52 * <p> 53 * GIT uses a subset of the available UNIX file permission bits. The 54 * <code>FileMode</code> class provides access to constants defining the modes 55 * actually used by GIT. 56 * </p> 57 */ 58 public abstract class FileMode { 59 /** 60 * Mask to apply to a file mode to obtain its type bits. 61 * 62 * @see #TYPE_TREE 63 * @see #TYPE_SYMLINK 64 * @see #TYPE_FILE 65 * @see #TYPE_GITLINK 66 * @see #TYPE_MISSING 67 */ 68 public static final int TYPE_MASK = 0170000; 69 70 /** Bit pattern for {@link #TYPE_MASK} matching {@link #TREE}. */ 71 public static final int TYPE_TREE = 0040000; 72 73 /** Bit pattern for {@link #TYPE_MASK} matching {@link #SYMLINK}. */ 74 public static final int TYPE_SYMLINK = 0120000; 75 76 /** Bit pattern for {@link #TYPE_MASK} matching {@link #REGULAR_FILE}. */ 77 public static final int TYPE_FILE = 0100000; 78 79 /** Bit pattern for {@link #TYPE_MASK} matching {@link #GITLINK}. */ 80 public static final int TYPE_GITLINK = 0160000; 81 82 /** Bit pattern for {@link #TYPE_MASK} matching {@link #MISSING}. */ 83 public static final int TYPE_MISSING = 0000000; 84 85 /** 86 * Mode indicating an entry is a tree (aka directory). 87 */ 88 public static final FileMode TREE = new FileMode(TYPE_TREE, 89 Constants.OBJ_TREE) { 90 @Override 91 public boolean equals(int modeBits) { 92 return (modeBits & TYPE_MASK) == TYPE_TREE; 93 } 94 }; 95 96 /** Mode indicating an entry is a symbolic link. */ 97 public static final FileMode SYMLINK = new FileMode(TYPE_SYMLINK, 98 Constants.OBJ_BLOB) { 99 @Override 100 public boolean equals(int modeBits) { 101 return (modeBits & TYPE_MASK) == TYPE_SYMLINK; 102 } 103 }; 104 105 /** Mode indicating an entry is a non-executable file. */ 106 public static final FileMode REGULAR_FILE = new FileMode(0100644, 107 Constants.OBJ_BLOB) { 108 @Override 109 public boolean equals(int modeBits) { 110 return (modeBits & TYPE_MASK) == TYPE_FILE && (modeBits & 0111) == 0; 111 } 112 }; 113 114 /** Mode indicating an entry is an executable file. */ 115 public static final FileMode EXECUTABLE_FILE = new FileMode(0100755, 116 Constants.OBJ_BLOB) { 117 @Override 118 public boolean equals(int modeBits) { 119 return (modeBits & TYPE_MASK) == TYPE_FILE && (modeBits & 0111) != 0; 120 } 121 }; 122 123 /** Mode indicating an entry is a submodule commit in another repository. */ 124 public static final FileMode GITLINK = new FileMode(TYPE_GITLINK, 125 Constants.OBJ_COMMIT) { 126 @Override 127 public boolean equals(int modeBits) { 128 return (modeBits & TYPE_MASK) == TYPE_GITLINK; 129 } 130 }; 131 132 /** Mode indicating an entry is missing during parallel walks. */ 133 public static final FileMode MISSING = new FileMode(TYPE_MISSING, 134 Constants.OBJ_BAD) { 135 @Override 136 public boolean equals(int modeBits) { 137 return modeBits == 0; 138 } 139 }; 140 141 /** 142 * Convert a set of mode bits into a FileMode enumerated value. 143 * 144 * @param bits 145 * the mode bits the caller has somehow obtained. 146 * @return the FileMode instance that represents the given bits. 147 */ 148 public static final FileMode fromBits(int bits) { 149 switch (bits & TYPE_MASK) { 150 case TYPE_MISSING: 151 if (bits == 0) 152 return MISSING; 153 break; 154 case TYPE_TREE: 155 return TREE; 156 case TYPE_FILE: 157 if ((bits & 0111) != 0) 158 return EXECUTABLE_FILE; 159 return REGULAR_FILE; 160 case TYPE_SYMLINK: 161 return SYMLINK; 162 case TYPE_GITLINK: 163 return GITLINK; 164 } 165 166 return new FileMode(bits, Constants.OBJ_BAD) { 167 @Override 168 public boolean equals(int a) { 169 return bits == a; 170 } 171 }; 172 } 173 174 private final byte[] octalBytes; 175 176 private final int modeBits; 177 178 private final int objectType; 179 180 private FileMode(int mode, int expType) { 181 modeBits = mode; 182 objectType = expType; 183 if (mode != 0) { 184 final byte[] tmp = new byte[10]; 185 int p = tmp.length; 186 187 while (mode != 0) { 188 tmp[--p] = (byte) ('0' + (mode & 07)); 189 mode >>= 3; 190 } 191 192 octalBytes = new byte[tmp.length - p]; 193 for (int k = 0; k < octalBytes.length; k++) { 194 octalBytes[k] = tmp[p + k]; 195 } 196 } else { 197 octalBytes = new byte[] { '0' }; 198 } 199 } 200 201 /** 202 * Test a file mode for equality with this 203 * {@link org.eclipse.jgit.lib.FileMode} object. 204 * 205 * @param modebits 206 * a int. 207 * @return true if the mode bits represent the same mode as this object 208 */ 209 public abstract boolean equals(int modebits); 210 211 /** 212 * Copy this mode as a sequence of octal US-ASCII bytes. 213 * <p> 214 * The mode is copied as a sequence of octal digits using the US-ASCII 215 * character encoding. The sequence does not use a leading '0' prefix to 216 * indicate octal notation. This method is suitable for generation of a mode 217 * string within a GIT tree object. 218 * </p> 219 * 220 * @param os 221 * stream to copy the mode to. 222 * @throws java.io.IOException 223 * the stream encountered an error during the copy. 224 */ 225 public void copyTo(OutputStream os) throws IOException { 226 os.write(octalBytes); 227 } 228 229 /** 230 * Copy this mode as a sequence of octal US-ASCII bytes. 231 * 232 * The mode is copied as a sequence of octal digits using the US-ASCII 233 * character encoding. The sequence does not use a leading '0' prefix to 234 * indicate octal notation. This method is suitable for generation of a mode 235 * string within a GIT tree object. 236 * 237 * @param buf 238 * buffer to copy the mode to. 239 * @param ptr 240 * position within {@code buf} for first digit. 241 */ 242 public void copyTo(byte[] buf, int ptr) { 243 System.arraycopy(octalBytes, 0, buf, ptr, octalBytes.length); 244 } 245 246 /** 247 * Copy the number of bytes written by {@link #copyTo(OutputStream)}. 248 * 249 * @return the number of bytes written by {@link #copyTo(OutputStream)}. 250 */ 251 public int copyToLength() { 252 return octalBytes.length; 253 } 254 255 /** 256 * Get the object type that should appear for this type of mode. 257 * <p> 258 * See the object type constants in {@link org.eclipse.jgit.lib.Constants}. 259 * 260 * @return one of the well known object type constants. 261 */ 262 public int getObjectType() { 263 return objectType; 264 } 265 266 /** 267 * {@inheritDoc} 268 * <p> 269 * Format this mode as an octal string (for debugging only). 270 */ 271 @Override 272 public String toString() { 273 return Integer.toOctalString(modeBits); 274 } 275 276 /** 277 * Get the mode bits as an integer. 278 * 279 * @return The mode bits as an integer. 280 */ 281 public int getBits() { 282 return modeBits; 283 } 284 }