FileMode.java
/*
* Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
* https://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
package org.eclipse.jgit.lib;
import java.io.IOException;
import java.io.OutputStream;
/**
* Constants describing various file modes recognized by GIT.
* <p>
* GIT uses a subset of the available UNIX file permission bits. The
* <code>FileMode</code> class provides access to constants defining the modes
* actually used by GIT.
* </p>
*/
public abstract class FileMode {
/**
* Mask to apply to a file mode to obtain its type bits.
*
* @see #TYPE_TREE
* @see #TYPE_SYMLINK
* @see #TYPE_FILE
* @see #TYPE_GITLINK
* @see #TYPE_MISSING
*/
public static final int TYPE_MASK = 0170000;
/** Bit pattern for {@link #TYPE_MASK} matching {@link #TREE}. */
public static final int TYPE_TREE = 0040000;
/** Bit pattern for {@link #TYPE_MASK} matching {@link #SYMLINK}. */
public static final int TYPE_SYMLINK = 0120000;
/** Bit pattern for {@link #TYPE_MASK} matching {@link #REGULAR_FILE}. */
public static final int TYPE_FILE = 0100000;
/** Bit pattern for {@link #TYPE_MASK} matching {@link #GITLINK}. */
public static final int TYPE_GITLINK = 0160000;
/** Bit pattern for {@link #TYPE_MASK} matching {@link #MISSING}. */
public static final int TYPE_MISSING = 0000000;
/**
* Mode indicating an entry is a tree (aka directory).
*/
public static final FileMode TREE = new FileMode(TYPE_TREE,
Constants.OBJ_TREE) {
@Override
@SuppressWarnings("NonOverridingEquals")
public boolean equals(int modeBits) {
return (modeBits & TYPE_MASK) == TYPE_TREE;
}
};
/** Mode indicating an entry is a symbolic link. */
public static final FileMode SYMLINK = new FileMode(TYPE_SYMLINK,
Constants.OBJ_BLOB) {
@Override
@SuppressWarnings("NonOverridingEquals")
public boolean equals(int modeBits) {
return (modeBits & TYPE_MASK) == TYPE_SYMLINK;
}
};
/** Mode indicating an entry is a non-executable file. */
public static final FileMode REGULAR_FILE = new FileMode(0100644,
Constants.OBJ_BLOB) {
@Override
@SuppressWarnings("NonOverridingEquals")
public boolean equals(int modeBits) {
return (modeBits & TYPE_MASK) == TYPE_FILE && (modeBits & 0111) == 0;
}
};
/** Mode indicating an entry is an executable file. */
public static final FileMode EXECUTABLE_FILE = new FileMode(0100755,
Constants.OBJ_BLOB) {
@Override
@SuppressWarnings("NonOverridingEquals")
public boolean equals(int modeBits) {
return (modeBits & TYPE_MASK) == TYPE_FILE && (modeBits & 0111) != 0;
}
};
/** Mode indicating an entry is a submodule commit in another repository. */
public static final FileMode GITLINK = new FileMode(TYPE_GITLINK,
Constants.OBJ_COMMIT) {
@Override
@SuppressWarnings("NonOverridingEquals")
public boolean equals(int modeBits) {
return (modeBits & TYPE_MASK) == TYPE_GITLINK;
}
};
/** Mode indicating an entry is missing during parallel walks. */
public static final FileMode MISSING = new FileMode(TYPE_MISSING,
Constants.OBJ_BAD) {
@Override
@SuppressWarnings("NonOverridingEquals")
public boolean equals(int modeBits) {
return modeBits == 0;
}
};
/**
* Convert a set of mode bits into a FileMode enumerated value.
*
* @param bits
* the mode bits the caller has somehow obtained.
* @return the FileMode instance that represents the given bits.
*/
public static final FileMode fromBits(int bits) {
switch (bits & TYPE_MASK) {
case TYPE_MISSING:
if (bits == 0)
return MISSING;
break;
case TYPE_TREE:
return TREE;
case TYPE_FILE:
if ((bits & 0111) != 0)
return EXECUTABLE_FILE;
return REGULAR_FILE;
case TYPE_SYMLINK:
return SYMLINK;
case TYPE_GITLINK:
return GITLINK;
}
return new FileMode(bits, Constants.OBJ_BAD) {
@Override
@SuppressWarnings("NonOverridingEquals")
public boolean equals(int a) {
return bits == a;
}
};
}
private final byte[] octalBytes;
private final int modeBits;
private final int objectType;
private FileMode(int mode, int expType) {
modeBits = mode;
objectType = expType;
if (mode != 0) {
final byte[] tmp = new byte[10];
int p = tmp.length;
while (mode != 0) {
tmp[--p] = (byte) ('0' + (mode & 07));
mode >>= 3;
}
octalBytes = new byte[tmp.length - p];
for (int k = 0; k < octalBytes.length; k++) {
octalBytes[k] = tmp[p + k];
}
} else {
octalBytes = new byte[] { '0' };
}
}
/**
* Test a file mode for equality with this
* {@link org.eclipse.jgit.lib.FileMode} object.
*
* @param modebits
* a int.
* @return true if the mode bits represent the same mode as this object
*/
@SuppressWarnings("NonOverridingEquals")
public abstract boolean equals(int modebits);
/**
* Copy this mode as a sequence of octal US-ASCII bytes.
* <p>
* The mode is copied as a sequence of octal digits using the US-ASCII
* character encoding. The sequence does not use a leading '0' prefix to
* indicate octal notation. This method is suitable for generation of a mode
* string within a GIT tree object.
* </p>
*
* @param os
* stream to copy the mode to.
* @throws java.io.IOException
* the stream encountered an error during the copy.
*/
public void copyTo(OutputStream os) throws IOException {
os.write(octalBytes);
}
/**
* Copy this mode as a sequence of octal US-ASCII bytes.
*
* The mode is copied as a sequence of octal digits using the US-ASCII
* character encoding. The sequence does not use a leading '0' prefix to
* indicate octal notation. This method is suitable for generation of a mode
* string within a GIT tree object.
*
* @param buf
* buffer to copy the mode to.
* @param ptr
* position within {@code buf} for first digit.
*/
public void copyTo(byte[] buf, int ptr) {
System.arraycopy(octalBytes, 0, buf, ptr, octalBytes.length);
}
/**
* Copy the number of bytes written by {@link #copyTo(OutputStream)}.
*
* @return the number of bytes written by {@link #copyTo(OutputStream)}.
*/
public int copyToLength() {
return octalBytes.length;
}
/**
* Get the object type that should appear for this type of mode.
* <p>
* See the object type constants in {@link org.eclipse.jgit.lib.Constants}.
*
* @return one of the well known object type constants.
*/
public int getObjectType() {
return objectType;
}
/**
* {@inheritDoc}
* <p>
* Format this mode as an octal string (for debugging only).
*/
@Override
public String toString() {
return Integer.toOctalString(modeBits);
}
/**
* Get the mode bits as an integer.
*
* @return The mode bits as an integer.
*/
public int getBits() {
return modeBits;
}
}