if (! path.exists()) return -1;\r
\r
int perm = configShared.getPerm();\r
- int mode = JnaUtils.getFilemode(path);\r
+ JnaUtils.Filestat stat = JnaUtils.getFilestat(path);\r
+ if (stat == null) return -1;\r
+ int mode = stat.mode;\r
if (mode < 0) return -1;\r
\r
+ // Now, here is the kicker: Under Linux, chmod'ing a sgid file whose guid is different from the process'\r
+ // effective guid will reset the sgid flag of the file. Since there is no way to get the sgid flag back in\r
+ // that case, we decide to rather not touch is and getting the right permissions will have to be achieved\r
+ // in a different way, e.g. by using an appropriate umask for the Gitblit process.\r
+ if (System.getProperty("os.name").toLowerCase().startsWith("linux")) {\r
+ if ( ((mode & (JnaUtils.S_ISGID | JnaUtils.S_ISUID)) != 0)\r
+ && stat.gid != JnaUtils.getegid() ) {\r
+ LOGGER.debug("Not adjusting permissions to prevent clearing suid/sgid bits for '" + path + "'" );\r
+ return 0;\r
+ }\r
+ }\r
+\r
// If the owner has no write access, delete it from group and other, too.\r
if ((mode & JnaUtils.S_IWUSR) == 0) perm &= ~0222;\r
// If the owner has execute access, set it for all blocks that have read access.\r
private interface UnixCLibrary extends Library {
public int chmod(String path, int mode);
+ public int getgid();
+ public int getegid();
+ }
+
+
+ public static int getgid()
+ {
+ 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();
}
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
}
}
- return mode;
+ return new Filestat(mode, Integer.parseInt(m.group(6)), Integer.parseInt(m.group(7)));
}
/**
- * Run the unix command 'ls -ldO' on a single file and return the resulting output line.
+ * 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.
*/
private static String runProcessLs(String path)
{
- String cmd = "ls -ld " + path;
+ String cmd = "ls -ldn " + path;
Runtime rt = Runtime.getRuntime();
Process pr = null;
InputStreamReader ir = null;
}\r
}\r
\r
+ @Test\r
+ public void testCreateRepositorySharedSgidParent() throws Exception {\r
+ if (! JnaUtils.isWindows()) {\r
+ String repositoryAll = "NewTestRepositoryAll.git";\r
+ String repositoryUmask = "NewTestRepositoryUmask.git";\r
+ String sgidParent = "sgid";\r
+ \r
+ File parent = new File(GitBlitSuite.REPOSITORIES, sgidParent);\r
+ File folder = null;\r
+ boolean parentExisted = parent.exists();\r
+ try {\r
+ if (!parentExisted) {\r
+ assertTrue("Could not create SGID parent folder.", parent.mkdir());\r
+ }\r
+ int mode = JnaUtils.getFilemode(parent);\r
+ assertTrue(mode > 0);\r
+ assertEquals(0, JnaUtils.setFilemode(parent, mode | JnaUtils.S_ISGID | JnaUtils.S_IWGRP));\r
+\r
+ Repository repository = JGitUtils.createRepository(parent, repositoryAll, "all");\r
+ folder = FileKey.resolve(new File(parent, repositoryAll), FS.DETECTED);\r
+ assertNotNull(repository);\r
+ \r
+ assertEquals("2", repository.getConfig().getString("core", null, "sharedRepository"));\r
+ \r
+ assertTrue(folder.exists());\r
+ mode = JnaUtils.getFilemode(folder);\r
+ assertEquals(JnaUtils.S_ISGID, mode & JnaUtils.S_ISGID);\r
+ \r
+ mode = JnaUtils.getFilemode(folder.getAbsolutePath() + "/HEAD");\r
+ assertEquals(JnaUtils.S_IRGRP | JnaUtils.S_IWGRP, mode & JnaUtils.S_IRWXG);\r
+ assertEquals(JnaUtils.S_IROTH, mode & JnaUtils.S_IRWXO);\r
+ \r
+ mode = JnaUtils.getFilemode(folder.getAbsolutePath() + "/config");\r
+ assertEquals(JnaUtils.S_IRGRP | JnaUtils.S_IWGRP, mode & JnaUtils.S_IRWXG);\r
+ assertEquals(JnaUtils.S_IROTH, mode & JnaUtils.S_IRWXO);\r
+ \r
+ repository.close();\r
+ RepositoryCache.close(repository);\r
+\r
+\r
+\r
+ repository = JGitUtils.createRepository(parent, repositoryUmask, "umask");\r
+ folder = FileKey.resolve(new File(parent, repositoryUmask), FS.DETECTED);\r
+ assertNotNull(repository);\r
+ \r
+ assertEquals(null, repository.getConfig().getString("core", null, "sharedRepository"));\r
+ \r
+ assertTrue(folder.exists());\r
+ mode = JnaUtils.getFilemode(folder);\r
+ assertEquals(JnaUtils.S_ISGID, mode & JnaUtils.S_ISGID);\r
+ \r
+ repository.close();\r
+ RepositoryCache.close(repository);\r
+ }\r
+ finally {\r
+ FileUtils.delete(new File(parent, repositoryAll), FileUtils.RECURSIVE | FileUtils.IGNORE_ERRORS);\r
+ FileUtils.delete(new File(parent, repositoryUmask), FileUtils.RECURSIVE | FileUtils.IGNORE_ERRORS);\r
+ if (!parentExisted) {\r
+ FileUtils.delete(parent, FileUtils.RECURSIVE | FileUtils.IGNORE_ERRORS);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
@Test\r
public void testRefs() throws Exception {\r
Repository repository = GitBlitSuite.getJGitRepository();\r
import java.io.File;
import java.io.IOException;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import org.apache.commons.io.FileUtils;
*/
public class JnaUtilsTest {
+ @Test
+ public void testGetgid() {
+ if (JnaUtils.isWindows()) {
+ try {
+ JnaUtils.getFilemode(GitBlitSuite.REPOSITORIES);
+ } catch(UnsupportedOperationException e) {}
+ }
+ else {
+ int gid = JnaUtils.getgid();
+ assertTrue(gid >= 0);
+ int egid = JnaUtils.getegid();
+ assertTrue(egid >= 0);
+ assertTrue("Really? You're running unit tests as root?!", gid > 0);
+ System.out.println("gid: " + gid + " egid: " + egid);
+ }
+ }
+
+
@Test
public void testGetFilemode() throws IOException {
if (JnaUtils.isWindows()) {
FileUtils.deleteDirectory(repository.getDirectory());
}
}
+
+
+ @Test
+ public void testGetFilestat() {
+ if (JnaUtils.isWindows()) {
+ try {
+ JnaUtils.getFilemode(GitBlitSuite.REPOSITORIES);
+ } catch(UnsupportedOperationException e) {}
+ }
+ else {
+ JnaUtils.Filestat stat = JnaUtils.getFilestat(GitBlitSuite.REPOSITORIES);
+ assertNotNull(stat);
+ assertTrue(stat.mode > 0);
+ assertTrue(stat.uid > 0);
+ assertTrue(stat.gid > 0);
+ }
+ }
+
+
}