View Javadoc
1   /*
2    * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
3    * Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org> and others
4    *
5    * This program and the accompanying materials are made available under the
6    * terms of the Eclipse Distribution License v. 1.0 which is available at
7    * https://www.eclipse.org/org/documents/edl-v10.php.
8    *
9    * SPDX-License-Identifier: BSD-3-Clause
10   */
11  
12  package org.eclipse.jgit.lib;
13  
14  import java.io.IOException;
15  import java.io.OutputStream;
16  
17  /**
18   * Constants describing various file modes recognized by GIT.
19   * <p>
20   * GIT uses a subset of the available UNIX file permission bits. The
21   * <code>FileMode</code> class provides access to constants defining the modes
22   * actually used by GIT.
23   * </p>
24   */
25  public abstract class FileMode {
26  	/**
27  	 * Mask to apply to a file mode to obtain its type bits.
28  	 *
29  	 * @see #TYPE_TREE
30  	 * @see #TYPE_SYMLINK
31  	 * @see #TYPE_FILE
32  	 * @see #TYPE_GITLINK
33  	 * @see #TYPE_MISSING
34  	 */
35  	public static final int TYPE_MASK = 0170000;
36  
37  	/** Bit pattern for {@link #TYPE_MASK} matching {@link #TREE}. */
38  	public static final int TYPE_TREE = 0040000;
39  
40  	/** Bit pattern for {@link #TYPE_MASK} matching {@link #SYMLINK}. */
41  	public static final int TYPE_SYMLINK = 0120000;
42  
43  	/** Bit pattern for {@link #TYPE_MASK} matching {@link #REGULAR_FILE}. */
44  	public static final int TYPE_FILE = 0100000;
45  
46  	/** Bit pattern for {@link #TYPE_MASK} matching {@link #GITLINK}. */
47  	public static final int TYPE_GITLINK = 0160000;
48  
49  	/** Bit pattern for {@link #TYPE_MASK} matching {@link #MISSING}. */
50  	public static final int TYPE_MISSING = 0000000;
51  
52  	/**
53  	 * Mode indicating an entry is a tree (aka directory).
54  	 */
55  	public static final FileModee.html#FileMode">FileMode TREE = new FileMode(TYPE_TREE,
56  			Constants.OBJ_TREE) {
57  		@Override
58  		@SuppressWarnings("NonOverridingEquals")
59  		public boolean equals(int modeBits) {
60  			return (modeBits & TYPE_MASK) == TYPE_TREE;
61  		}
62  	};
63  
64  	/** Mode indicating an entry is a symbolic link. */
65  	public static final FileModetml#FileMode">FileMode SYMLINK = new FileMode(TYPE_SYMLINK,
66  			Constants.OBJ_BLOB) {
67  		@Override
68  		@SuppressWarnings("NonOverridingEquals")
69  		public boolean equals(int modeBits) {
70  			return (modeBits & TYPE_MASK) == TYPE_SYMLINK;
71  		}
72  	};
73  
74  	/** Mode indicating an entry is a non-executable file. */
75  	public static final FileModeileMode">FileMode REGULAR_FILE = new FileMode(0100644,
76  			Constants.OBJ_BLOB) {
77  		@Override
78  		@SuppressWarnings("NonOverridingEquals")
79  		public boolean equals(int modeBits) {
80  			return (modeBits & TYPE_MASK) == TYPE_FILE && (modeBits & 0111) == 0;
81  		}
82  	};
83  
84  	/** Mode indicating an entry is an executable file. */
85  	public static final FileModeMode">FileMode EXECUTABLE_FILE = new FileMode(0100755,
86  			Constants.OBJ_BLOB) {
87  		@Override
88  		@SuppressWarnings("NonOverridingEquals")
89  		public boolean equals(int modeBits) {
90  			return (modeBits & TYPE_MASK) == TYPE_FILE && (modeBits & 0111) != 0;
91  		}
92  	};
93  
94  	/** Mode indicating an entry is a submodule commit in another repository. */
95  	public static final FileModetml#FileMode">FileMode GITLINK = new FileMode(TYPE_GITLINK,
96  			Constants.OBJ_COMMIT) {
97  		@Override
98  		@SuppressWarnings("NonOverridingEquals")
99  		public boolean equals(int modeBits) {
100 			return (modeBits & TYPE_MASK) == TYPE_GITLINK;
101 		}
102 	};
103 
104 	/** Mode indicating an entry is missing during parallel walks. */
105 	public static final FileModetml#FileMode">FileMode MISSING = new FileMode(TYPE_MISSING,
106 			Constants.OBJ_BAD) {
107 		@Override
108 		@SuppressWarnings("NonOverridingEquals")
109 		public boolean equals(int modeBits) {
110 			return modeBits == 0;
111 		}
112 	};
113 
114 	/**
115 	 * Convert a set of mode bits into a FileMode enumerated value.
116 	 *
117 	 * @param bits
118 	 *            the mode bits the caller has somehow obtained.
119 	 * @return the FileMode instance that represents the given bits.
120 	 */
121 	public static final FileMode fromBits(int bits) {
122 		switch (bits & TYPE_MASK) {
123 		case TYPE_MISSING:
124 			if (bits == 0)
125 				return MISSING;
126 			break;
127 		case TYPE_TREE:
128 			return TREE;
129 		case TYPE_FILE:
130 			if ((bits & 0111) != 0)
131 				return EXECUTABLE_FILE;
132 			return REGULAR_FILE;
133 		case TYPE_SYMLINK:
134 			return SYMLINK;
135 		case TYPE_GITLINK:
136 			return GITLINK;
137 		}
138 
139 		return new FileMode(bits, Constants.OBJ_BAD) {
140 			@Override
141 			@SuppressWarnings("NonOverridingEquals")
142 			public boolean equals(int a) {
143 				return bits == a;
144 			}
145 		};
146 	}
147 
148 	private final byte[] octalBytes;
149 
150 	private final int modeBits;
151 
152 	private final int objectType;
153 
154 	private FileMode(int mode, int expType) {
155 		modeBits = mode;
156 		objectType = expType;
157 		if (mode != 0) {
158 			final byte[] tmp = new byte[10];
159 			int p = tmp.length;
160 
161 			while (mode != 0) {
162 				tmp[--p] = (byte) ('0' + (mode & 07));
163 				mode >>= 3;
164 			}
165 
166 			octalBytes = new byte[tmp.length - p];
167 			for (int k = 0; k < octalBytes.length; k++) {
168 				octalBytes[k] = tmp[p + k];
169 			}
170 		} else {
171 			octalBytes = new byte[] { '0' };
172 		}
173 	}
174 
175 	/**
176 	 * Test a file mode for equality with this
177 	 * {@link org.eclipse.jgit.lib.FileMode} object.
178 	 *
179 	 * @param modebits
180 	 *            a int.
181 	 * @return true if the mode bits represent the same mode as this object
182 	 */
183 	@SuppressWarnings("NonOverridingEquals")
184 	public abstract boolean equals(int modebits);
185 
186 	/**
187 	 * Copy this mode as a sequence of octal US-ASCII bytes.
188 	 * <p>
189 	 * The mode is copied as a sequence of octal digits using the US-ASCII
190 	 * character encoding. The sequence does not use a leading '0' prefix to
191 	 * indicate octal notation. This method is suitable for generation of a mode
192 	 * string within a GIT tree object.
193 	 * </p>
194 	 *
195 	 * @param os
196 	 *            stream to copy the mode to.
197 	 * @throws java.io.IOException
198 	 *             the stream encountered an error during the copy.
199 	 */
200 	public void copyTo(OutputStream os) throws IOException {
201 		os.write(octalBytes);
202 	}
203 
204 	/**
205 	 * Copy this mode as a sequence of octal US-ASCII bytes.
206 	 *
207 	 * The mode is copied as a sequence of octal digits using the US-ASCII
208 	 * character encoding. The sequence does not use a leading '0' prefix to
209 	 * indicate octal notation. This method is suitable for generation of a mode
210 	 * string within a GIT tree object.
211 	 *
212 	 * @param buf
213 	 *            buffer to copy the mode to.
214 	 * @param ptr
215 	 *            position within {@code buf} for first digit.
216 	 */
217 	public void copyTo(byte[] buf, int ptr) {
218 		System.arraycopy(octalBytes, 0, buf, ptr, octalBytes.length);
219 	}
220 
221 	/**
222 	 * Copy the number of bytes written by {@link #copyTo(OutputStream)}.
223 	 *
224 	 * @return the number of bytes written by {@link #copyTo(OutputStream)}.
225 	 */
226 	public int copyToLength() {
227 		return octalBytes.length;
228 	}
229 
230 	/**
231 	 * Get the object type that should appear for this type of mode.
232 	 * <p>
233 	 * See the object type constants in {@link org.eclipse.jgit.lib.Constants}.
234 	 *
235 	 * @return one of the well known object type constants.
236 	 */
237 	public int getObjectType() {
238 		return objectType;
239 	}
240 
241 	/**
242 	 * {@inheritDoc}
243 	 * <p>
244 	 * Format this mode as an octal string (for debugging only).
245 	 */
246 	@Override
247 	public String toString() {
248 		return Integer.toOctalString(modeBits);
249 	}
250 
251 	/**
252 	 * Get the mode bits as an integer.
253 	 *
254 	 * @return The mode bits as an integer.
255 	 */
256 	public int getBits() {
257 		return modeBits;
258 	}
259 }