Procházet zdrojové kódy

Merge branch 'init-shared' of https://github.com/fzs/gitblit into prefixes

tags/v1.4.0
James Moger před 10 roky
rodič
revize
35f55ae7e0

+ 1
- 1
.classpath Zobrazit soubor

@@ -37,6 +37,7 @@
<classpathentry kind="lib" path="ext/jcalendar-1.3.2.jar" />
<classpathentry kind="lib" path="ext/commons-compress-1.4.1.jar" sourcepath="ext/src/commons-compress-1.4.1.jar" />
<classpathentry kind="lib" path="ext/xz-1.0.jar" sourcepath="ext/src/xz-1.0.jar" />
<classpathentry kind="lib" path="ext/commons-io-2.2.jar" sourcepath="ext/src/commons-io-2.2.jar" />
<classpathentry kind="lib" path="ext/force-partner-api-24.0.0.jar" sourcepath="ext/src/force-partner-api-24.0.0.jar" />
<classpathentry kind="lib" path="ext/force-wsc-24.0.0.jar" sourcepath="ext/src/force-wsc-24.0.0.jar" />
<classpathentry kind="lib" path="ext/js-1.7R2.jar" sourcepath="ext/src/js-1.7R2.jar" />
@@ -60,7 +61,6 @@
<classpathentry kind="lib" path="ext/httpcore-4.2.1.jar" sourcepath="ext/src/httpcore-4.2.1.jar" />
<classpathentry kind="lib" path="ext/commons-logging-1.1.1.jar" sourcepath="ext/src/commons-logging-1.1.1.jar" />
<classpathentry kind="lib" path="ext/commons-exec-1.1.jar" sourcepath="ext/src/commons-exec-1.1.jar" />
<classpathentry kind="lib" path="ext/commons-io-2.2.jar" sourcepath="ext/src/commons-io-2.2.jar" />
<classpathentry kind="output" path="bin/classes" />
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER" />
</classpath>

+ 1
- 0
build.moxie Zobrazit soubor

@@ -148,6 +148,7 @@ dependencies:
- compile 'org.apache.ivy:ivy:2.2.0' :war
- compile 'com.toedter:jcalendar:1.3.2' :authority
- compile 'org.apache.commons:commons-compress:1.4.1' :war
- compile 'commons-io:commons-io:2.2' :war
- compile 'com.force.api:force-partner-api:24.0.0' :war
- compile 'org.freemarker:freemarker:2.3.19' :war
- compile 'com.github.dblock.waffle:waffle-jna:1.5' :war

+ 11
- 11
gitblit.iml Zobrazit soubor

@@ -380,6 +380,17 @@
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="commons-io-2.2.jar">
<CLASSES>
<root url="jar://$MODULE_DIR$/ext/commons-io-2.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$MODULE_DIR$/ext/src/commons-io-2.2.jar!/" />
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="force-partner-api-24.0.0.jar">
<CLASSES>
@@ -633,17 +644,6 @@
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library" scope="TEST">
<library name="commons-io-2.2.jar">
<CLASSES>
<root url="jar://$MODULE_DIR$/ext/commons-io-2.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$MODULE_DIR$/ext/src/commons-io-2.2.jar!/" />
</SOURCES>
</library>
</orderEntry>
<orderEntry type="inheritedJdk" />
</component>
</module>

+ 9
- 0
src/main/distrib/data/gitblit.properties Zobrazit soubor

@@ -191,6 +191,15 @@ git.userRepositoryPrefix = ~
# SINCE 1.3.0
git.defaultIncrementalPushTagPrefix = r
# In an Unix environment where mixed access methods exist for shared repositories,
# the repository should be created with 'git init --shared' to make sure that
# it can be accessed e.g. via ssh (user git) and http (user www-data).
# Valid values are the values available for the '--shared' option. The the manual
# page for 'git init' for more information on shared repositories.
#
# SINCE 1.3.2
git.createRepositoriesShared = false
# Enable JGit-based garbage collection. (!!EXPERIMENTAL!!)
#
# USE AT YOUR OWN RISK!

+ 9
- 2
src/main/java/com/gitblit/GitBlit.java Zobrazit soubor

@@ -2427,7 +2427,8 @@ public class GitBlit implements ServletContextListener {
}
// create repository
logger.info("create repository " + repository.name);
r = JGitUtils.createRepository(repositoriesFolder, repository.name);
String shared = getString(Keys.git.createRepositoriesShared, "FALSE");
r = JGitUtils.createRepository(repositoriesFolder, repository.name, shared);
} else {
// rename repository
if (!repositoryName.equalsIgnoreCase(repository.name)) {
@@ -2529,7 +2530,13 @@ public class GitBlit implements ServletContextListener {
// close the repository object
r.close();
}

// Adjust permissions in case we updated the config files
JGitUtils.adjustSharedPerm(new File(r.getDirectory().getAbsolutePath(), "config"),
getString(Keys.git.createRepositoriesShared, "FALSE"));
JGitUtils.adjustSharedPerm(new File(r.getDirectory().getAbsolutePath(), "HEAD"),
getString(Keys.git.createRepositoriesShared, "FALSE"));

// update repository cache
removeFromCachedRepositoryList(repositoryName);
// model will actually be replaced on next load because config is stale

+ 179
- 3
src/main/java/com/gitblit/utils/JGitUtils.java Zobrazit soubor

@@ -32,6 +32,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.FetchCommand;
import org.eclipse.jgit.api.Git;
@@ -58,6 +59,7 @@ import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryCache.FileKey;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.lib.TreeFormatter;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -259,14 +261,188 @@ public class JGitUtils {
* @return Repository
*/
public static Repository createRepository(File repositoriesFolder, String name) {
return createRepository(repositoriesFolder, name, "FALSE");
}
/**
* 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 {
Git git = Git.init().setDirectory(new File(repositoriesFolder, name)).setBare(true).call();
return git.getRepository();
} catch (GitAPIException e) {
Repository repo = null;
try {
Git git = Git.init().setDirectory(new File(repositoriesFolder, name)).setBare(true).call();
repo = git.getRepository();
} catch (GitAPIException e) {
throw new RuntimeException(e);
}
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()) {
Iterator<File> iter = org.apache.commons.io.FileUtils.iterateFilesAndDirs(repo.getDirectory(),
TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE);
// Adjust permissions on file/directory
while (iter.hasNext()) {
adjustSharedPerm(iter.next(), sharedRepository);
}
}
}
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;
private 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 ) {
if (intValue == 0) return "0";
return String.format("0%o", intValue);
}
return enumValue.getConfigValue();
}
int getPerm() {
if ( enumValue == GitConfigSharedRepositoryValue.Oxxx ) return intValue;
return enumValue.getPerm();
}
boolean isCustom() {
return enumValue == GitConfigSharedRepositoryValue.Oxxx;
}
boolean isShared() {
return (enumValue.getPerm() > 0) || enumValue == GitConfigSharedRepositoryValue.Oxxx;
}
}
/**
* Adjust file permissions of a file/directory for shared repositories
*
* @param path
* File that should get its permissions changed.
* @param configShared
* Configuration string value for the shared mode.
* @return Upon successful completion, a value of 0 is returned. Otherwise, a value of -1 is returned.
*/
public static int adjustSharedPerm(File path, String configShared) {
return adjustSharedPerm(path, new GitConfigSharedRepository(configShared));
}
/**
* Adjust file permissions of a file/directory for shared repositories
*
* @param path
* File that should get its permissions changed.
* @param configShared
* Configuration setting for the shared mode.
* @return Upon successful completion, a value of 0 is returned. Otherwise, a value of -1 is returned.
*/
public static int adjustSharedPerm(File path, GitConfigSharedRepository configShared) {
if (! configShared.isShared()) return 0;
if (! path.exists()) return -1;
int perm = configShared.getPerm();
JnaUtils.Filestat stat = JnaUtils.getFilestat(path);
if (stat == null) return -1;
int mode = stat.mode;
if (mode < 0) return -1;
// Now, here is the kicker: Under Linux, chmod'ing a sgid file whose guid is different from the process'
// effective guid will reset the sgid flag of the file. Since there is no way to get the sgid flag back in
// that case, we decide to rather not touch is and getting the right permissions will have to be achieved
// in a different way, e.g. by using an appropriate umask for the Gitblit process.
if (System.getProperty("os.name").toLowerCase().startsWith("linux")) {
if ( ((mode & (JnaUtils.S_ISGID | JnaUtils.S_ISUID)) != 0)
&& stat.gid != JnaUtils.getegid() ) {
LOGGER.debug("Not adjusting permissions to prevent clearing suid/sgid bits for '" + path + "'" );
return 0;
}
}
// If the owner has no write access, delete it from group and other, too.
if ((mode & JnaUtils.S_IWUSR) == 0) perm &= ~0222;
// If the owner has execute access, set it for all blocks that have read access.
if ((mode & JnaUtils.S_IXUSR) == JnaUtils.S_IXUSR) perm |= (perm & 0444) >> 2;
if (configShared.isCustom()) {
// Use the custom value for access permissions.
mode = (mode & ~0777) | perm;
}
else {
// Just add necessary bits to existing permissions.
mode |= perm;
}
if (path.isDirectory()) {
mode |= (mode & 0444) >> 2;
mode |= JnaUtils.S_ISGID;
}
return JnaUtils.setFilemode(path, mode);
}
/**
* Returns a list of repository names in the specified folder.
*

+ 364
- 0
src/main/java/com/gitblit/utils/JnaUtils.java Zobrazit soubor

@@ -0,0 +1,364 @@
/*
* 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_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_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_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);

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");
}


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();
}


/**
* 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()) {
throw new UnsupportedOperationException("The method JnaUtils.getFilemode is not supported under Windows.");
}

return getUnixCLibrary().chmod(path, mode);
}



/**
* 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 null;
}

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 null;
}

// 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 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 -ldn " + 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;
}

}

+ 134
- 0
src/test/java/com/gitblit/tests/JGitUtilsTest.java Zobrazit soubor

@@ -52,6 +52,7 @@ import com.gitblit.models.PathModel.PathChangeModel;
import com.gitblit.models.RefModel;
import com.gitblit.utils.CompressionUtils;
import com.gitblit.utils.JGitUtils;
import com.gitblit.utils.JnaUtils;
import com.gitblit.utils.StringUtils;
public class JGitUtilsTest {
@@ -148,6 +149,139 @@ public class JGitUtilsTest {
}
}
@Test
public void testCreateRepositoryShared() throws Exception {
String[] repositories = { "NewSharedTestRepository.git" };
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("1", repository.getConfig().getString("core", null, "sharedRepository"));
assertTrue(folder.exists());
if (! JnaUtils.isWindows()) {
int mode = JnaUtils.getFilemode(folder);
assertEquals(JnaUtils.S_ISGID, mode & JnaUtils.S_ISGID);
assertEquals(JnaUtils.S_IRWXG, mode & JnaUtils.S_IRWXG);
mode = JnaUtils.getFilemode(folder.getAbsolutePath() + "/HEAD");
assertEquals(JnaUtils.S_IRGRP | JnaUtils.S_IWGRP, mode & JnaUtils.S_IRWXG);
mode = JnaUtils.getFilemode(folder.getAbsolutePath() + "/config");
assertEquals(JnaUtils.S_IRGRP | JnaUtils.S_IWGRP, mode & JnaUtils.S_IRWXG);
}
repository.close();
RepositoryCache.close(repository);
FileUtils.delete(repository.getDirectory(), FileUtils.RECURSIVE);
}
}
@Test
public void testCreateRepositorySharedCustom() throws Exception {
String[] repositories = { "NewSharedTestRepository.git" };
for (String repositoryName : repositories) {
Repository repository = JGitUtils.createRepository(GitBlitSuite.REPOSITORIES,
repositoryName, "660");
File folder = FileKey.resolve(new File(GitBlitSuite.REPOSITORIES, repositoryName),
FS.DETECTED);
assertNotNull(repository);
assertFalse(JGitUtils.hasCommits(repository));
assertNull(JGitUtils.getFirstCommit(repository, null));
assertEquals("0660", repository.getConfig().getString("core", null, "sharedRepository"));
assertTrue(folder.exists());
if (! JnaUtils.isWindows()) {
int mode = JnaUtils.getFilemode(folder);
assertEquals(JnaUtils.S_ISGID, mode & JnaUtils.S_ISGID);
assertEquals(JnaUtils.S_IRWXG, mode & JnaUtils.S_IRWXG);
assertEquals(0, mode & JnaUtils.S_IRWXO);
mode = JnaUtils.getFilemode(folder.getAbsolutePath() + "/HEAD");
assertEquals(JnaUtils.S_IRGRP | JnaUtils.S_IWGRP, mode & JnaUtils.S_IRWXG);
assertEquals(0, mode & JnaUtils.S_IRWXO);
mode = JnaUtils.getFilemode(folder.getAbsolutePath() + "/config");
assertEquals(JnaUtils.S_IRGRP | JnaUtils.S_IWGRP, mode & JnaUtils.S_IRWXG);
assertEquals(0, mode & JnaUtils.S_IRWXO);
}
repository.close();
RepositoryCache.close(repository);
FileUtils.delete(repository.getDirectory(), FileUtils.RECURSIVE);
}
}
@Test
public void testCreateRepositorySharedSgidParent() throws Exception {
if (! JnaUtils.isWindows()) {
String repositoryAll = "NewTestRepositoryAll.git";
String repositoryUmask = "NewTestRepositoryUmask.git";
String sgidParent = "sgid";
File parent = new File(GitBlitSuite.REPOSITORIES, sgidParent);
File folder = null;
boolean parentExisted = parent.exists();
try {
if (!parentExisted) {
assertTrue("Could not create SGID parent folder.", parent.mkdir());
}
int mode = JnaUtils.getFilemode(parent);
assertTrue(mode > 0);
assertEquals(0, JnaUtils.setFilemode(parent, mode | JnaUtils.S_ISGID | JnaUtils.S_IWGRP));
Repository repository = JGitUtils.createRepository(parent, repositoryAll, "all");
folder = FileKey.resolve(new File(parent, repositoryAll), FS.DETECTED);
assertNotNull(repository);
assertEquals("2", repository.getConfig().getString("core", null, "sharedRepository"));
assertTrue(folder.exists());
mode = JnaUtils.getFilemode(folder);
assertEquals(JnaUtils.S_ISGID, mode & JnaUtils.S_ISGID);
mode = JnaUtils.getFilemode(folder.getAbsolutePath() + "/HEAD");
assertEquals(JnaUtils.S_IRGRP | JnaUtils.S_IWGRP, mode & JnaUtils.S_IRWXG);
assertEquals(JnaUtils.S_IROTH, mode & JnaUtils.S_IRWXO);
mode = JnaUtils.getFilemode(folder.getAbsolutePath() + "/config");
assertEquals(JnaUtils.S_IRGRP | JnaUtils.S_IWGRP, mode & JnaUtils.S_IRWXG);
assertEquals(JnaUtils.S_IROTH, mode & JnaUtils.S_IRWXO);
repository.close();
RepositoryCache.close(repository);
repository = JGitUtils.createRepository(parent, repositoryUmask, "umask");
folder = FileKey.resolve(new File(parent, repositoryUmask), FS.DETECTED);
assertNotNull(repository);
assertEquals(null, repository.getConfig().getString("core", null, "sharedRepository"));
assertTrue(folder.exists());
mode = JnaUtils.getFilemode(folder);
assertEquals(JnaUtils.S_ISGID, mode & JnaUtils.S_ISGID);
repository.close();
RepositoryCache.close(repository);
}
finally {
FileUtils.delete(new File(parent, repositoryAll), FileUtils.RECURSIVE | FileUtils.IGNORE_ERRORS);
FileUtils.delete(new File(parent, repositoryUmask), FileUtils.RECURSIVE | FileUtils.IGNORE_ERRORS);
if (!parentExisted) {
FileUtils.delete(parent, FileUtils.RECURSIVE | FileUtils.IGNORE_ERRORS);
}
}
}
}
@Test
public void testRefs() throws Exception {
Repository repository = GitBlitSuite.getJGitRepository();

+ 152
- 0
src/test/java/com/gitblit/tests/JnaUtilsTest.java Zobrazit soubor

@@ -0,0 +1,152 @@
/*
* 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.assertNotNull;
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 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()) {
try {
JnaUtils.getFilemode(GitBlitSuite.REPOSITORIES);
} catch(UnsupportedOperationException e) {}
}
else {
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 {
if (JnaUtils.isWindows()) {
try {
JnaUtils.getFilemode(GitBlitSuite.REPOSITORIES);
} catch(UnsupportedOperationException e) {}
}
else {
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());
}
}


@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);
}
}


}

Načítá se…
Zrušit
Uložit