summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/main/java/com/gitblit/utils/JGitUtils.java192
-rw-r--r--src/main/java/com/gitblit/utils/JnaUtils.java226
-rw-r--r--src/test/java/com/gitblit/tests/JGitUtilsTest.java21
-rw-r--r--src/test/java/com/gitblit/tests/JnaUtilsTest.java100
4 files changed, 440 insertions, 99 deletions
diff --git a/src/main/java/com/gitblit/utils/JGitUtils.java b/src/main/java/com/gitblit/utils/JGitUtils.java
index 345375a9..03b54ee9 100644
--- a/src/main/java/com/gitblit/utils/JGitUtils.java
+++ b/src/main/java/com/gitblit/utils/JGitUtils.java
@@ -89,8 +89,6 @@ import com.gitblit.models.PathModel;
import com.gitblit.models.PathModel.PathChangeModel;
import com.gitblit.models.RefModel;
import com.gitblit.models.SubmoduleModel;
-import com.sun.jna.Library;
-import com.sun.jna.Native;
/**
* Collection of static methods for retrieving information from a repository.
@@ -270,103 +268,99 @@ public class JGitUtils {
}
}
- /**
- * Creates a bare, shared repository.
- *
- * @param repositoriesFolder
- * @param name
- * @param shared
- * the setting for the --shared option of "git init".
- * @return Repository
- */
- public static Repository createRepository(File repositoriesFolder, String name, String shared) {
- try {
- Repository repo = createRepository(repositoriesFolder, name);
-
- GitConfigSharedRepository sharedRepository = new GitConfigSharedRepository(shared);
- if (sharedRepository.isShared()) {
- StoredConfig config = repo.getConfig();
- config.setString("core", null, "sharedRepository", sharedRepository.getValue());
- config.setBoolean("receive", null, "denyNonFastforwards", true);
- config.save();
-
- if (! System.getProperty("os.name").toLowerCase().startsWith("windows")) {
- final CLibrary libc = (CLibrary) Native.loadLibrary("c", CLibrary.class);
-
- //libc.chmod("/path/to/file", 0755);
- }
- }
-
- return repo;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- interface CLibrary extends Library {
- public int chmod(String path, int mode);
- }
- private enum GitConfigSharedRepositoryValue {
- UMASK("0", 0), FALSE("0", 0), OFF("0", 0), NO("0", 0),
- GROUP("1", 0660), TRUE("1", 0660), ON("1", 0660), YES("1", 0660),
- ALL("2", 0664), WORLD("2", 0664), EVERYBODY("2", 0664),
- Oxxx(null, -1);
-
- private String configValue;
- private int permValue;
- private GitConfigSharedRepositoryValue(String config, int perm) { configValue = config; permValue = perm; };
-
- public String getConfigValue() { return configValue; };
- public int getPerm() { return permValue; };
-
- }
- private static class GitConfigSharedRepository
- {
- private int intValue;
- GitConfigSharedRepositoryValue enumValue;
-
- GitConfigSharedRepository(String s)
- {
- if ( s == null || s.trim().isEmpty() ) {
- enumValue = GitConfigSharedRepositoryValue.GROUP;
- }
- else {
- try {
- // Try one of the string values
- enumValue = GitConfigSharedRepositoryValue.valueOf(s.trim().toUpperCase());
- } catch (IllegalArgumentException iae) {
- try {
- // Try if this is an octal number
- int i = Integer.parseInt(s, 8);
- if ( (i & 0600) != 0600 ) {
- String msg = String.format("Problem with core.sharedRepository filemode value (0%03o).\nThe owner of files must always have read and write permissions.", i);
- throw new IllegalArgumentException(msg);
- }
- intValue = i & 0666;
- enumValue = GitConfigSharedRepositoryValue.Oxxx;
- } catch (NumberFormatException nfe) {
- throw new IllegalArgumentException("Bad configuration value for 'shared': '" + s + "'");
- }
- }
- }
- }
-
- String getValue()
- {
- if ( enumValue == GitConfigSharedRepositoryValue.Oxxx ) return Integer.toOctalString(intValue);
- return enumValue.getConfigValue();
- }
-
- int getPerm()
- {
- if ( enumValue == GitConfigSharedRepositoryValue.Oxxx ) return intValue;
- return enumValue.getPerm();
- }
-
- boolean isShared()
- {
- return (enumValue.getPerm() > 0) || enumValue == GitConfigSharedRepositoryValue.Oxxx;
- }
- }
+ /**
+ * Creates a bare, shared repository.
+ *
+ * @param repositoriesFolder
+ * @param name
+ * @param shared
+ * the setting for the --shared option of "git init".
+ * @return Repository
+ */
+ public static Repository createRepository(File repositoriesFolder, String name, String shared) {
+ try {
+ Repository repo = createRepository(repositoriesFolder, name);
+
+ GitConfigSharedRepository sharedRepository = new GitConfigSharedRepository(shared);
+ if (sharedRepository.isShared()) {
+ StoredConfig config = repo.getConfig();
+ config.setString("core", null, "sharedRepository", sharedRepository.getValue());
+ config.setBoolean("receive", null, "denyNonFastforwards", true);
+ config.save();
+
+ if (! JnaUtils.isWindows()) {
+
+ //libc.chmod("/path/to/file", 0755);
+ }
+ }
+
+ return repo;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ private enum GitConfigSharedRepositoryValue {
+ UMASK("0", 0), FALSE("0", 0), OFF("0", 0), NO("0", 0),
+ GROUP("1", 0660), TRUE("1", 0660), ON("1", 0660), YES("1", 0660),
+ ALL("2", 0664), WORLD("2", 0664), EVERYBODY("2", 0664),
+ Oxxx(null, -1);
+
+ private String configValue;
+ private int permValue;
+ private GitConfigSharedRepositoryValue(String config, int perm) { configValue = config; permValue = perm; };
+
+ public String getConfigValue() { return configValue; };
+ public int getPerm() { return permValue; };
+
+ }
+ private static class GitConfigSharedRepository
+ {
+ private int intValue;
+ GitConfigSharedRepositoryValue enumValue;
+
+ GitConfigSharedRepository(String s)
+ {
+ if ( s == null || s.trim().isEmpty() ) {
+ enumValue = GitConfigSharedRepositoryValue.GROUP;
+ }
+ else {
+ try {
+ // Try one of the string values
+ enumValue = GitConfigSharedRepositoryValue.valueOf(s.trim().toUpperCase());
+ } catch (IllegalArgumentException iae) {
+ try {
+ // Try if this is an octal number
+ int i = Integer.parseInt(s, 8);
+ if ( (i & 0600) != 0600 ) {
+ String msg = String.format("Problem with core.sharedRepository filemode value (0%03o).\nThe owner of files must always have read and write permissions.", i);
+ throw new IllegalArgumentException(msg);
+ }
+ intValue = i & 0666;
+ enumValue = GitConfigSharedRepositoryValue.Oxxx;
+ } catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException("Bad configuration value for 'shared': '" + s + "'");
+ }
+ }
+ }
+ }
+
+ String getValue()
+ {
+ if ( enumValue == GitConfigSharedRepositoryValue.Oxxx ) return Integer.toOctalString(intValue);
+ return enumValue.getConfigValue();
+ }
+
+ int getPerm()
+ {
+ if ( enumValue == GitConfigSharedRepositoryValue.Oxxx ) return intValue;
+ return enumValue.getPerm();
+ }
+
+ boolean isShared()
+ {
+ return (enumValue.getPerm() > 0) || enumValue == GitConfigSharedRepositoryValue.Oxxx;
+ }
+ }
/**
diff --git a/src/main/java/com/gitblit/utils/JnaUtils.java b/src/main/java/com/gitblit/utils/JnaUtils.java
new file mode 100644
index 00000000..b7d7209f
--- /dev/null
+++ b/src/main/java/com/gitblit/utils/JnaUtils.java
@@ -0,0 +1,226 @@
+/*
+ * 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;
+ }
+
+}
diff --git a/src/test/java/com/gitblit/tests/JGitUtilsTest.java b/src/test/java/com/gitblit/tests/JGitUtilsTest.java
index 375dbd5a..4affca2d 100644
--- a/src/test/java/com/gitblit/tests/JGitUtilsTest.java
+++ b/src/test/java/com/gitblit/tests/JGitUtilsTest.java
@@ -149,6 +149,27 @@ public class JGitUtilsTest {
}
@Test
+ public void testCreateRepositoryShared() throws Exception {
+ String[] repositories = { "NewTestRepository.git", "NewTestRepository" };
+ for (String repositoryName : repositories) {
+ Repository repository = JGitUtils.createRepository(GitBlitSuite.REPOSITORIES,
+ repositoryName, "group");
+ File folder = FileKey.resolve(new File(GitBlitSuite.REPOSITORIES, repositoryName),
+ FS.DETECTED);
+ assertNotNull(repository);
+ assertFalse(JGitUtils.hasCommits(repository));
+ assertNull(JGitUtils.getFirstCommit(repository, null));
+ assertEquals(folder.lastModified(), JGitUtils.getFirstChange(repository, null)
+ .getTime());
+ assertEquals(folder.lastModified(), JGitUtils.getLastChange(repository).when.getTime());
+ assertNull(JGitUtils.getCommit(repository, null));
+ repository.close();
+ RepositoryCache.close(repository);
+// FileUtils.delete(repository.getDirectory(), FileUtils.RECURSIVE);
+ }
+ }
+
+ @Test
public void testRefs() throws Exception {
Repository repository = GitBlitSuite.getJGitRepository();
Map<ObjectId, List<RefModel>> map = JGitUtils.getAllRefs(repository);
diff --git a/src/test/java/com/gitblit/tests/JnaUtilsTest.java b/src/test/java/com/gitblit/tests/JnaUtilsTest.java
new file mode 100644
index 00000000..574686ba
--- /dev/null
+++ b/src/test/java/com/gitblit/tests/JnaUtilsTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2011 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.tests;
+
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.JnaUtils;
+import java.io.File;
+import java.io.IOException;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.commons.io.FileUtils;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.RepositoryCache;
+import org.eclipse.jgit.lib.RepositoryCache.FileKey;
+import org.eclipse.jgit.util.FS;
+import org.junit.Test;
+
+/**
+ *
+ * @author Florian Zschocke
+ */
+public class JnaUtilsTest {
+
+ @Test
+ public void testGetFilemode() throws IOException {
+ String repositoryName = "NewJnaTestRepository.git";
+ Repository repository = JGitUtils.createRepository(GitBlitSuite.REPOSITORIES, repositoryName);
+ File folder = FileKey.resolve(new File(GitBlitSuite.REPOSITORIES, repositoryName), FS.DETECTED);
+ assertTrue(folder.exists());
+
+ int mode = JnaUtils.getFilemode(folder);
+ assertTrue(mode > 0);
+ assertEquals(JnaUtils.S_IFDIR, (mode & JnaUtils.S_IFMT)); // directory
+ assertEquals(JnaUtils.S_IRUSR | JnaUtils.S_IWUSR | JnaUtils.S_IXUSR, (mode & JnaUtils.S_IRWXU)); // owner full access
+
+ mode = JnaUtils.getFilemode(folder.getAbsolutePath() + "/config");
+ assertTrue(mode > 0);
+ assertEquals(JnaUtils.S_IFREG, (mode & JnaUtils.S_IFMT)); // directory
+ assertEquals(JnaUtils.S_IRUSR | JnaUtils.S_IWUSR, (mode & JnaUtils.S_IRWXU)); // owner full access
+
+ repository.close();
+ RepositoryCache.close(repository);
+ FileUtils.deleteDirectory(repository.getDirectory());
+ }
+
+
+ @Test
+ public void testSetFilemode() throws IOException {
+ String repositoryName = "NewJnaTestRepository.git";
+ Repository repository = JGitUtils.createRepository(GitBlitSuite.REPOSITORIES, repositoryName);
+ File folder = FileKey.resolve(new File(GitBlitSuite.REPOSITORIES, repositoryName), FS.DETECTED);
+ assertTrue(folder.exists());
+
+ File path = new File(folder, "refs");
+ int mode = JnaUtils.getFilemode(path);
+ assertTrue(mode > 0);
+ assertEquals(JnaUtils.S_IFDIR, (mode & JnaUtils.S_IFMT)); // directory
+ assertEquals(JnaUtils.S_IRUSR | JnaUtils.S_IWUSR | JnaUtils.S_IXUSR, (mode & JnaUtils.S_IRWXU)); // owner full access
+
+ mode |= JnaUtils.S_ISGID;
+ mode |= JnaUtils.S_IRWXG;
+ int ret = JnaUtils.setFilemode(path, mode);
+ assertEquals(0, ret);
+ mode = JnaUtils.getFilemode(path);
+ assertTrue(mode > 0);
+ assertEquals(JnaUtils.S_ISGID, (mode & JnaUtils.S_ISGID)); // set-gid-bit set
+ assertEquals(JnaUtils.S_IRGRP | JnaUtils.S_IWGRP | JnaUtils.S_IXGRP, (mode & JnaUtils.S_IRWXG)); // group full access
+
+ path = new File(folder, "config");
+ mode = JnaUtils.getFilemode(path.getAbsolutePath());
+ assertTrue(mode > 0);
+ assertEquals(JnaUtils.S_IFREG, (mode & JnaUtils.S_IFMT)); // directory
+ assertEquals(JnaUtils.S_IRUSR | JnaUtils.S_IWUSR, (mode & JnaUtils.S_IRWXU)); // owner full access
+
+ mode |= (JnaUtils.S_IRGRP | JnaUtils.S_IWGRP);
+ ret = JnaUtils.setFilemode(path.getAbsolutePath(), mode);
+ assertEquals(0, ret);
+ mode = JnaUtils.getFilemode(path.getAbsolutePath());
+ assertTrue(mode > 0);
+ assertEquals(JnaUtils.S_IRGRP | JnaUtils.S_IWGRP, (mode & JnaUtils.S_IRWXG)); // group full access
+
+ repository.close();
+ RepositoryCache.close(repository);
+ FileUtils.deleteDirectory(repository.getDirectory());
+ }
+}