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