From a502d96a860456ec5e8c96761db70f7cabb74751 Mon Sep 17 00:00:00 2001 From: Paul Martin <paul@paulsputer.com> Date: Sat, 30 Apr 2016 04:19:14 -0400 Subject: [PATCH] Merge pull request #1073 from gitblit/1062-DocEditorUpdates --- src/main/java/com/gitblit/utils/JnaUtils.java | 204 ++++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 171 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/gitblit/utils/JnaUtils.java b/src/main/java/com/gitblit/utils/JnaUtils.java index b7d7209..2b80719 100644 --- a/src/main/java/com/gitblit/utils/JnaUtils.java +++ b/src/main/java/com/gitblit/utils/JnaUtils.java @@ -15,9 +15,6 @@ */ 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; @@ -28,37 +25,40 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.sun.jna.Library; +import com.sun.jna.Native; + /** * 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; // set user id on execution + public static final int S_ISGID = 0002000; // set group id on execution + public static final int S_ISVTX = 0001000; // sticky bit, save swapped text even after use - 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; // RWX mask for owner + public static final int S_IRUSR = 0000400; // read permission for owner + public static final int S_IWUSR = 0000200; // write permission for owner + public static final int S_IXUSR = 0000100; // execute/search permission for owner + public static final int S_IRWXG = 0000070; // RWX mask for group + public static final int S_IRGRP = 0000040; // read permission for group + public static final int S_IWGRP = 0000020; // write permission for group + public static final int S_IXGRP = 0000010; // execute/search permission for group + public static final int S_IRWXO = 0000007; // RWX mask for other + public static final int S_IROTH = 0000004; // read permission for other + public static final int S_IWOTH = 0000002; // write permission for other + public static final int S_IXOTH = 0000001; // execute/search permission for other - 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; + public static final int S_IFMT = 0170000; // type of file mask + public static final int S_IFIFO = 0010000; // named pipe (fifo) + public static final int S_IFCHR = 0020000; // character special device + public static final int S_IFDIR = 0040000; // directory + public static final int S_IFBLK = 0060000; // block special device + public static final int S_IFREG = 0100000; // regular file + public static final int S_IFLNK = 0120000; // symbolic link + public static final int S_IFSOCK = 0140000; // socket private static final Logger LOGGER = LoggerFactory.getLogger(JGitUtils.class); @@ -66,6 +66,11 @@ private static UnixCLibrary unixlibc = null; + /** + * Utility method to check if the JVM is running on a Windows OS. + * + * @return true, if the system property 'os.name' starts with 'Windows'. + */ public static boolean isWindows() { return System.getProperty("os.name").toLowerCase().startsWith("windows"); @@ -74,14 +79,62 @@ private interface UnixCLibrary extends Library { public int chmod(String path, int mode); + public int getgid(); + public int getegid(); } - public static int setFilemode(File path, int mode) + public static int getgid() { - return setFilemode(path.getAbsolutePath(), mode); + if (isWindows()) { + throw new UnsupportedOperationException("The method JnaUtils.getgid is not supported under Windows."); + } + + return getUnixCLibrary().getgid(); } + + public static int getegid() + { + if (isWindows()) { + throw new UnsupportedOperationException("The method JnaUtils.getegid is not supported under Windows."); + } + + return getUnixCLibrary().getegid(); + } + + + /** + * Set the permission bits of a file. + * + * The permission bits are set to the provided mode. This method is only + * implemented for OSes of the Unix family and makes use of the 'chmod' + * function of the native C library. See 'man 2 chmod' for more information. + * + * @param path + * File/directory to set the permission bits for. + * @param mode + * A mode created from or'd permission bit masks S_I* + * @return Upon successful completion, a value of 0 returned. Otherwise, a value of -1 is returned. + */ + public static int setFilemode(File file, int mode) + { + return setFilemode(file.getAbsolutePath(), mode); + } + + /** + * Set the permission bits of a file. + * + * The permission bits are set to the provided mode. This method is only + * implemented for OSes of the Unix family and makes use of the 'chmod' + * function of the native C library. See 'man 2 chmod' for more information. + * + * @param path + * Path to a file/directory to set the permission bits for. + * @param mode + * A mode created from or'd permission bit masks S_I* + * @return Upon successful completion, a value of 0 returned. Otherwise, a value of -1 is returned. + */ public static int setFilemode(String path, int mode) { if (isWindows()) { @@ -93,32 +146,110 @@ + /** + * Get the file mode bits of a file. + * + * This method is only implemented for OSes of the Unix family. It returns the file mode + * information as available in the st_mode member of the resulting struct stat when calling + * 'lstat' on a file. + * + * @param path + * File/directory to get the file mode from. + * @return Upon successful completion, the file mode bits are returned. Otherwise, a value of -1 is returned. + */ public static int getFilemode(File path) { return getFilemode(path.getAbsolutePath()); } + /** + * Get the file mode bits of a file. + * + * This method is only implemented for OSes of the Unix family. It returns the file mode + * information as available in the st_mode member of the resulting struct stat when calling + * 'lstat' on a file. + * + * @param path + * Path to a file/directory to get the file mode from. + * @return Upon successful completion, the file mode bits are returned. Otherwise, a value of -1 is returned. + */ public static int getFilemode(String path) { if (isWindows()) { throw new UnsupportedOperationException("The method JnaUtils.getFilemode is not supported under Windows."); } + Filestat stat = getFilestat(path); + if ( stat == null ) return -1; + return stat.mode; + } + + + /** + * Status information of a file. + */ + public static class Filestat + { + public int mode; // file mode, permissions, type + public int uid; // user Id of owner + public int gid; // group Id of owner + + Filestat(int mode, int uid, int gid) { + this.mode = mode; this.uid = uid; this.gid = gid; + } + } + + + /** + * Get Unix file status information for a file. + * + * This method is only implemented for OSes of the Unix family. It returns file status + * information for a file. Currently this is the file mode, the user id and group id of the owner. + * + * @param path + * File/directory to get the file status from. + * @return Upon successful completion, a Filestat object containing the file information is returned. + * Otherwise, null is returned. + */ + public static Filestat getFilestat(File path) + { + return getFilestat(path.getAbsolutePath()); + } + + + /** + * Get Unix file status information for a file. + * + * This method is only implemented for OSes of the Unix family. It returns file status + * information for a file. Currently this is the file mode, the user id and group id of the owner. + * + * @param path + * Path to a file/directory to get the file status from. + * @return Upon successful completion, a Filestat object containing the file information is returned. + * Otherwise, null is returned. + */ + public static Filestat getFilestat(String path) + { + if (isWindows()) { + throw new UnsupportedOperationException("The method JnaUtils.getFilestat is not supported under Windows."); + } + int mode = 0; // Use a Runtime, because implementing stat() via JNA is just too much trouble. + // This could be done with the 'stat' command, too. But that may have a shell specific implementation, so we use 'ls' instead. String lsLine = runProcessLs(path); if (lsLine == null) { LOGGER.debug("Could not get file information for path " + path); - return -1; + return null; } - Pattern p = Pattern.compile("^(([-bcdlsp])([-r][-w][-xSs])([-r][-w][-xSs])([-r][-w][-xTt])) "); + Pattern p = Pattern.compile("^(([-bcdlspCDMnP?])([-r][-w][-xSs])([-r][-w][-xSs])([-r][-w][-xTt]))[@+.]? +[0-9]+ +([0-9]+) +([0-9]+) "); Matcher m = p.matcher(lsLine); if ( !m.lookingAt() ) { LOGGER.debug("Could not parse valid file mode information for path " + path); - return -1; + return null; } // Parse mode string to mode bits @@ -174,13 +305,20 @@ } } - return mode; + return new Filestat(mode, Integer.parseInt(m.group(6)), Integer.parseInt(m.group(7))); } + /** + * Run the unix command 'ls -ldn' on a single file and return the resulting output line. + * + * @param path + * Path to a single file or directory. + * @return The first line of output from the 'ls' command. Null, if an error occurred and no line could be read. + */ private static String runProcessLs(String path) { - String cmd = "ls -ldO " + path; + String cmd = "ls -ldn " + path; Runtime rt = Runtime.getRuntime(); Process pr = null; InputStreamReader ir = null; -- Gitblit v1.9.1