@ -66,140 +66,70 @@ import org.eclipse.jgit.lib.Repository;
* @since 3 . 0
* /
public class FS_POSIX extends FS {
private static final int DEFAULT_UMASK = 0022 ;
private volatile int umask = - 1 ;
static {
String umask = readUmask ( ) ;
// umask return value consists of 3 or 4 digits, like "002" or "0002"
if ( umask ! = null & & umask . length ( ) > 0 & & umask . matches ( "\\d{3,4}" ) ) { //$NON-NLS-1$
EXECUTE_FOR_OTHERS = isGranted ( PosixFilePermission . OTHERS_EXECUTE ,
umask ) ;
EXECUTE_FOR_GROUP = isGranted ( PosixFilePermission . GROUP_EXECUTE ,
umask ) ;
} else {
EXECUTE_FOR_OTHERS = null ;
EXECUTE_FOR_GROUP = null ;
}
/** Default constructor. */
protected FS_POSIX ( ) {
}
/ * *
* @since 4 . 0
* /
protected static final Boolean EXECUTE_FOR_OTHERS ;
/ * *
* @since 4 . 0
* Constructor
*
* @param src
* FS to copy some settings from
* /
protected static final Boolean EXECUTE_FOR_GROUP ;
protected FS_POSIX ( FS src ) {
super ( src ) ;
if ( src instanceof FS_POSIX ) {
umask = ( ( FS_POSIX ) src ) . umask ;
}
}
@Override
public FS newInstance ( ) {
return new FS_POSIX ( ) ;
return new FS_POSIX ( this ) ;
}
/ * *
* Derives requested permission from given octal umask value as defined e . g .
* in < a href = "http://linux.die.net/man/2/umask" > http : //linux.die.net/man/2/
* umask < / a > .
* < p >
* The umask expected here must consist of 3 or 4 digits . Last three digits
* are significant here because they represent file permissions granted to
* the "owner" , "group" and "others" ( in this order ) .
* < p >
* Each single digit from the umask represents 3 bits of the mask standing
* for "<b>r</b>ead, <b>w</b>rite, e<b>x</b>ecute" permissions ( in this
* order ) .
* < p >
* The possible umask values table :
*
* < pre >
* Value : Bits : Abbr . : Permission
* 0 : 000 : rwx : read , write and execute
* 1 : 001 : rw : read and write
* 2 : 010 : rx : read and execute
* 3 : 011 : r : read only
* 4 : 100 : wx : write and execute
* 5 : 101 : w : write only
* 6 : 110 : x : execute only
* 7 : 111 : : no permissions
* < / pre >
* < p >
* Note , that umask value is used to "mask" the requested permissions on
* file creation by combining the requested permission bit with the
* < b > negated < / b > value of the umask bit .
* < p >
* Simply speaking , if a bit is < b > not < / b > set in the umask , then the
* appropriate right < b > will < / b > be granted < b > if < / b > requested . If a bit is
* set in the umask value , then the appropriate permission will be not
* granted .
* < p >
* Example :
* < li > umask 023 ( "000 010 011" or rwx rx r ) combined with the request to
* create an executable file with full set of permissions for everyone ( 777 )
* results in the file with permissions 754 ( rwx rx r ) .
* < li > umask 002 ( "000 000 010" or rwx rwx rx ) combined with the request to
* create an executable file with full set of permissions for everyone ( 777 )
* results in the file with permissions 775 ( rwx rwx rx ) .
* < li > umask 002 ( "000 000 010" or rwx rwx rx ) combined with the request to
* create a file without executable rights for everyone ( 666 ) results in the
* file with permissions 664 ( rw rw r ) .
* Set the umask , overriding any value observed from the shell .
*
* @param p
* non null permission
* @param umask
* octal umask value represented by at least three digits . The
* digits ( read from the end to beginning of the umask ) represent
* permissions for "others" , "group" and "owner" .
*
* @return true if the requested permission is set according to given umask
* mask to apply when creating files .
* @since 4 . 0
* /
protected static Boolean isGranted ( PosixFilePermission p , String umask ) {
char val ;
switch ( p ) {
case OTHERS_EXECUTE :
// Read last digit, because umask is ordered as: User/Group/Others.
val = umask . charAt ( umask . length ( ) - 1 ) ;
return isExecuteGranted ( val ) ;
case GROUP_EXECUTE :
val = umask . charAt ( umask . length ( ) - 2 ) ;
return isExecuteGranted ( val ) ;
default :
throw new UnsupportedOperationException (
"isGranted() for " + p + " is not implemented!" ) ; //$NON-NLS-1$ //$NON-NLS-2$
}
public void setUmask ( int umask ) {
this . umask = umask ;
}
/ * *
* @param c
* character representing octal permission value from the table
* in { @link # isGranted ( PosixFilePermission , String ) }
* @return true if the "execute" permission is granted according to given
* character
* /
private static Boolean isExecuteGranted ( char c ) {
if ( c = = '0' | | c = = '2' | | c = = '4' | | c = = '6' )
return Boolean . TRUE ;
return Boolean . FALSE ;
private int umask ( ) {
int u = umask ;
if ( u = = - 1 ) {
u = readUmask ( ) ;
umask = u ;
}
return u ;
}
/ * *
* @return umask returned from running umask command in a shell
* @since 4 . 0
* /
protected static String readUmask ( ) {
Process p ;
/** @return mask returned from running {@code umask} command in shell. */
private static int readUmask ( ) {
try {
p = Runtime . getRuntime ( ) . exec (
new String [ ] { "sh" , "-c" , "umask" } , null , null ) ; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
Process p = Runtime . getRuntime ( ) . exec (
new String [ ] { "sh" , "-c" , "umask" } , //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
null , null ) ;
try ( BufferedReader lineRead = new BufferedReader (
new InputStreamReader ( p . getInputStream ( ) , Charset
. defaultCharset ( ) . name ( ) ) ) ) {
p . waitFor ( ) ;
return lineRead . readLine ( ) ;
if ( p . waitFor ( ) = = 0 ) {
String s = lineRead . readLine ( ) ;
if ( s . matches ( "0?\\d{3}" ) ) { //$NON-NLS-1$
return Integer . parseInt ( s , 8 ) ;
}
}
return DEFAULT_UMASK ;
}
} catch ( Exception e ) {
return null ;
return DEFAULT_UMASK ;
}
}
@ -229,23 +159,6 @@ public class FS_POSIX extends FS {
return null ;
}
/ * *
* Default constructor
* /
protected FS_POSIX ( ) {
super ( ) ;
}
/ * *
* Constructor
*
* @param src
* FS to copy some settings from
* /
protected FS_POSIX ( FS src ) {
super ( src ) ;
}
@Override
public boolean isCaseSensitive ( ) {
return ! SystemReader . getInstance ( ) . isMacOS ( ) ;
@ -265,35 +178,40 @@ public class FS_POSIX extends FS {
public boolean setExecute ( File f , boolean canExecute ) {
if ( ! isFile ( f ) )
return false ;
// only if the execute has to be set, and we know the umask
if ( canExecute & & EXECUTE_FOR_OTHERS ! = null ) {
try {
Path path = f . toPath ( ) ;
Set < PosixFilePermission > pset = Files
. getPosixFilePermissions ( path ) ;
// user is always allowed to set execute
pset . add ( PosixFilePermission . OWNER_EXECUTE ) ;
if ( EXECUTE_FOR_GROUP . booleanValue ( ) )
pset . add ( PosixFilePermission . GROUP_EXECUTE ) ;
if ( EXECUTE_FOR_OTHERS . booleanValue ( ) )
pset . add ( PosixFilePermission . OTHERS_EXECUTE ) ;
Files . setPosixFilePermissions ( path , pset ) ;
return true ;
} catch ( IOException e ) {
// The interface doesn't allow to throw IOException
final boolean debug = Boolean . parseBoolean ( SystemReader
. getInstance ( ) . getProperty ( "jgit.fs.debug" ) ) ; //$NON-NLS-1$
if ( debug )
System . err . println ( e ) ;
return false ;
}
if ( ! canExecute )
return f . setExecutable ( false ) ;
try {
Path path = f . toPath ( ) ;
Set < PosixFilePermission > pset = Files . getPosixFilePermissions ( path ) ;
// owner (user) is always allowed to execute.
pset . add ( PosixFilePermission . OWNER_EXECUTE ) ;
int mask = umask ( ) ;
apply ( pset , mask , PosixFilePermission . GROUP_EXECUTE , 1 < < 3 ) ;
apply ( pset , mask , PosixFilePermission . OTHERS_EXECUTE , 1 ) ;
Files . setPosixFilePermissions ( path , pset ) ;
return true ;
} catch ( IOException e ) {
// The interface doesn't allow to throw IOException
final boolean debug = Boolean . parseBoolean ( SystemReader
. getInstance ( ) . getProperty ( "jgit.fs.debug" ) ) ; //$NON-NLS-1$
if ( debug )
System . err . println ( e ) ;
return false ;
}
}
private static void apply ( Set < PosixFilePermission > set ,
int umask , PosixFilePermission perm , int test ) {
if ( ( umask & test ) = = 0 ) {
// If bit is clear in umask, permission is allowed.
set . add ( perm ) ;
} else {
// If bit is set in umask, permission is denied.
set . remove ( perm ) ;
}
// if umask is not working for some reason: fall back to default (buggy)
// implementation which does not consider umask: see bug 424395
return f . setExecutable ( canExecute ) ;
}
@Override