/*
|
* Copyright 2013 gitblit.com.
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
package com.gitblit.utils;
|
|
import com.sun.jna.Library;
|
import com.sun.jna.Native;
|
|
import java.io.BufferedReader;
|
import java.io.File;
|
import java.io.IOException;
|
import java.io.InputStreamReader;
|
import java.util.regex.Matcher;
|
import java.util.regex.Pattern;
|
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
|
/**
|
* Collection of static methods to access native OS library functionality.
|
*
|
* @author Florian Zschocke
|
*/
|
public class JnaUtils {
|
public static final int S_IFMT = 0170000;
|
public static final int S_IFIFO = 0010000;
|
public static final int S_IFCHR = 0020000;
|
public static final int S_IFDIR = 0040000;
|
public static final int S_IFBLK = 0060000;
|
public static final int S_IFREG = 0100000;
|
public static final int S_IFLNK = 0120000;
|
public static final int S_IFSOCK = 0140000;
|
|
public static final int S_ISUID = 0004000;
|
public static final int S_ISGID = 0002000;
|
public static final int S_ISVTX = 0001000;
|
|
public static final int S_IRWXU = 0000700;
|
public static final int S_IRUSR = 0000400;
|
public static final int S_IWUSR = 0000200;
|
public static final int S_IXUSR = 0000100;
|
public static final int S_IRWXG = 0000070;
|
public static final int S_IRGRP = 0000040;
|
public static final int S_IWGRP = 0000020;
|
public static final int S_IXGRP = 0000010;
|
public static final int S_IRWXO = 0000007;
|
public static final int S_IROTH = 0000004;
|
public static final int S_IWOTH = 0000002;
|
public static final int S_IXOTH = 0000001;
|
|
|
private static final Logger LOGGER = LoggerFactory.getLogger(JGitUtils.class);
|
|
private static UnixCLibrary unixlibc = null;
|
|
|
public static boolean isWindows()
|
{
|
return System.getProperty("os.name").toLowerCase().startsWith("windows");
|
}
|
|
|
private interface UnixCLibrary extends Library {
|
public int chmod(String path, int mode);
|
}
|
|
|
public static int setFilemode(File path, int mode)
|
{
|
return setFilemode(path.getAbsolutePath(), mode);
|
}
|
|
public static int setFilemode(String path, int mode)
|
{
|
if (isWindows()) {
|
throw new UnsupportedOperationException("The method JnaUtils.getFilemode is not supported under Windows.");
|
}
|
|
return getUnixCLibrary().chmod(path, mode);
|
}
|
|
|
|
public static int getFilemode(File path)
|
{
|
return getFilemode(path.getAbsolutePath());
|
}
|
|
public static int getFilemode(String path)
|
{
|
if (isWindows()) {
|
throw new UnsupportedOperationException("The method JnaUtils.getFilemode is not supported under Windows.");
|
}
|
|
|
int mode = 0;
|
|
// Use a Runtime, because implementing stat() via JNA is just too much trouble.
|
String lsLine = runProcessLs(path);
|
if (lsLine == null) {
|
LOGGER.debug("Could not get file information for path " + path);
|
return -1;
|
}
|
|
Pattern p = Pattern.compile("^(([-bcdlsp])([-r][-w][-xSs])([-r][-w][-xSs])([-r][-w][-xTt])) ");
|
Matcher m = p.matcher(lsLine);
|
if ( !m.lookingAt() ) {
|
LOGGER.debug("Could not parse valid file mode information for path " + path);
|
return -1;
|
}
|
|
// Parse mode string to mode bits
|
String group = m.group(2);
|
switch (group.charAt(0)) {
|
case 'p' :
|
mode |= 0010000; break;
|
case 'c':
|
mode |= 0020000; break;
|
case 'd':
|
mode |= 0040000; break;
|
case 'b':
|
mode |= 0060000; break;
|
case '-':
|
mode |= 0100000; break;
|
case 'l':
|
mode |= 0120000; break;
|
case 's':
|
mode |= 0140000; break;
|
}
|
|
for ( int i = 0; i < 3; i++) {
|
group = m.group(3 + i);
|
switch (group.charAt(0)) {
|
case 'r':
|
mode |= (0400 >> i*3); break;
|
case '-':
|
break;
|
}
|
|
switch (group.charAt(1)) {
|
case 'w':
|
mode |= (0200 >> i*3); break;
|
case '-':
|
break;
|
}
|
|
switch (group.charAt(2)) {
|
case 'x':
|
mode |= (0100 >> i*3); break;
|
case 'S':
|
mode |= (04000 >> i); break;
|
case 's':
|
mode |= (0100 >> i*3);
|
mode |= (04000 >> i); break;
|
case 'T':
|
mode |= 01000; break;
|
case 't':
|
mode |= (0100 >> i*3);
|
mode |= 01000; break;
|
case '-':
|
break;
|
}
|
}
|
|
return mode;
|
}
|
|
|
private static String runProcessLs(String path)
|
{
|
String cmd = "ls -ldO " + path;
|
Runtime rt = Runtime.getRuntime();
|
Process pr = null;
|
InputStreamReader ir = null;
|
BufferedReader br = null;
|
String output = null;
|
|
try {
|
pr = rt.exec(cmd);
|
ir = new InputStreamReader(pr.getInputStream());
|
br = new BufferedReader(ir);
|
|
output = br.readLine();
|
|
while (br.readLine() != null) ; // Swallow remaining output
|
}
|
catch (IOException e) {
|
LOGGER.debug("Exception while running unix command '" + cmd + "': " + e);
|
}
|
finally {
|
if (pr != null) try { pr.waitFor(); } catch (Exception ignored) {}
|
|
if (br != null) try { br.close(); } catch (Exception ignored) {}
|
if (ir != null) try { ir.close(); } catch (Exception ignored) {}
|
|
if (pr != null) try { pr.getOutputStream().close(); } catch (Exception ignored) {}
|
if (pr != null) try { pr.getInputStream().close(); } catch (Exception ignored) {}
|
if (pr != null) try { pr.getErrorStream().close(); } catch (Exception ignored) {}
|
}
|
|
return output;
|
}
|
|
|
private static UnixCLibrary getUnixCLibrary()
|
{
|
if (unixlibc == null) {
|
unixlibc = (UnixCLibrary) Native.loadLibrary("c", UnixCLibrary.class);
|
if (unixlibc == null) throw new RuntimeException("Could not initialize native C library.");
|
}
|
return unixlibc;
|
}
|
|
}
|