From 8a67d9dcdcc63fe48c97e83ffbc2a643eee2ed60 Mon Sep 17 00:00:00 2001 From: Florian Zschocke Date: Sat, 17 Aug 2013 18:37:41 +0200 Subject: Add proper implementation of methods in JnaUtils. Implement the methods getFilemode and setFilemode in JnaUtils. Not using the libc names as we don't necessarily use JNA and because it is not necessarily a one to one mapping. --- src/test/java/com/gitblit/tests/JGitUtilsTest.java | 21 +++++ src/test/java/com/gitblit/tests/JnaUtilsTest.java | 100 +++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 src/test/java/com/gitblit/tests/JnaUtilsTest.java (limited to 'src/test/java') 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 @@ -148,6 +148,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(); 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()); + } +} -- cgit v1.2.3 From e85277e1de9f59ac45df5ffd84c5d9be0e4d20d2 Mon Sep 17 00:00:00 2001 From: Florian Zschocke Date: Tue, 20 Aug 2013 10:58:51 +0200 Subject: Implement adjusting file permissions for shared repositories. Implement adjusting file and directory permissions for shared repositories in JGitUtils. --- src/main/java/com/gitblit/utils/JGitUtils.java | 82 +++++++++++++++++----- src/test/java/com/gitblit/tests/JGitUtilsTest.java | 21 ++++-- 2 files changed, 78 insertions(+), 25 deletions(-) (limited to 'src/test/java') diff --git a/src/main/java/com/gitblit/utils/JGitUtils.java b/src/main/java/com/gitblit/utils/JGitUtils.java index 03b54ee9..49b3ad70 100644 --- a/src/main/java/com/gitblit/utils/JGitUtils.java +++ b/src/main/java/com/gitblit/utils/JGitUtils.java @@ -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; @@ -260,12 +261,7 @@ public class JGitUtils { * @return Repository */ public static Repository createRepository(File repositoriesFolder, String name) { - try { - Git git = Git.init().setDirectory(new File(repositoriesFolder, name)).setBare(true).call(); - return git.getRepository(); - } catch (GitAPIException e) { - throw new RuntimeException(e); - } + return createRepository(repositoriesFolder, name, "FALSE"); } /** @@ -279,7 +275,13 @@ public class JGitUtils { */ public static Repository createRepository(File repositoriesFolder, String name, String shared) { try { - Repository repo = createRepository(repositoriesFolder, name); + 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()) { @@ -289,8 +291,12 @@ public class JGitUtils { config.save(); if (! JnaUtils.isWindows()) { - - //libc.chmod("/path/to/file", 0755); + Iterator 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); + } } } @@ -299,7 +305,9 @@ public class JGitUtils { throw new RuntimeException(e); } } - private enum GitConfigSharedRepositoryValue { + + 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), @@ -313,13 +321,13 @@ public class JGitUtils { public int getPerm() { return permValue; }; } + private static class GitConfigSharedRepository { private int intValue; - GitConfigSharedRepositoryValue enumValue; + private GitConfigSharedRepositoryValue enumValue; - GitConfigSharedRepository(String s) - { + GitConfigSharedRepository(String s) { if ( s == null || s.trim().isEmpty() ) { enumValue = GitConfigSharedRepositoryValue.GROUP; } @@ -344,25 +352,61 @@ public class JGitUtils { } } - String getValue() - { + String getValue() { if ( enumValue == GitConfigSharedRepositoryValue.Oxxx ) return Integer.toOctalString(intValue); return enumValue.getConfigValue(); } - int getPerm() - { + int getPerm() { if ( enumValue == GitConfigSharedRepositoryValue.Oxxx ) return intValue; return enumValue.getPerm(); } - boolean isShared() - { + boolean isCustom() { + return enumValue == GitConfigSharedRepositoryValue.Oxxx; + } + + boolean isShared() { return (enumValue.getPerm() > 0) || enumValue == GitConfigSharedRepositoryValue.Oxxx; } } + public static int adjustSharedPerm(File path, String configShared) { + return adjustSharedPerm(path, new GitConfigSharedRepository(configShared)); + } + + + public static int adjustSharedPerm(File path, GitConfigSharedRepository configShared) { + if (! configShared.isShared()) return 0; + + int perm = configShared.getPerm(); + int mode = JnaUtils.getFilemode(path); + if (mode < 0) return -1; + + // 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. * diff --git a/src/test/java/com/gitblit/tests/JGitUtilsTest.java b/src/test/java/com/gitblit/tests/JGitUtilsTest.java index 4affca2d..6f86b9f7 100644 --- a/src/test/java/com/gitblit/tests/JGitUtilsTest.java +++ b/src/test/java/com/gitblit/tests/JGitUtilsTest.java @@ -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 { @@ -150,7 +151,7 @@ public class JGitUtilsTest { @Test public void testCreateRepositoryShared() throws Exception { - String[] repositories = { "NewTestRepository.git", "NewTestRepository" }; + String[] repositories = { "NewSharedTestRepository.git" }; for (String repositoryName : repositories) { Repository repository = JGitUtils.createRepository(GitBlitSuite.REPOSITORIES, repositoryName, "group"); @@ -159,13 +160,21 @@ public class JGitUtilsTest { 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)); + + assertTrue(folder.exists()); + 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); + FileUtils.delete(repository.getDirectory(), FileUtils.RECURSIVE); } } -- cgit v1.2.3 From 9d2f661602049e0edbdac4fdcb2adb6b1f71b5de Mon Sep 17 00:00:00 2001 From: Florian Zschocke Date: Tue, 20 Aug 2013 19:42:17 +0200 Subject: Adjust unit tests for Windows. --- src/test/java/com/gitblit/tests/JGitUtilsTest.java | 18 ++-- src/test/java/com/gitblit/tests/JnaUtilsTest.java | 106 ++++++++++++--------- 2 files changed, 71 insertions(+), 53 deletions(-) (limited to 'src/test/java') diff --git a/src/test/java/com/gitblit/tests/JGitUtilsTest.java b/src/test/java/com/gitblit/tests/JGitUtilsTest.java index 6f86b9f7..f18c05f8 100644 --- a/src/test/java/com/gitblit/tests/JGitUtilsTest.java +++ b/src/test/java/com/gitblit/tests/JGitUtilsTest.java @@ -161,16 +161,20 @@ public class JGitUtilsTest { assertFalse(JGitUtils.hasCommits(repository)); assertNull(JGitUtils.getFirstCommit(repository, null)); + assertEquals("1", repository.getConfig().getString("core", null, "sharedRepository")); + assertTrue(folder.exists()); - int mode = JnaUtils.getFilemode(folder); - assertEquals(JnaUtils.S_ISGID, mode & JnaUtils.S_ISGID); - assertEquals(JnaUtils.S_IRWXG, mode & JnaUtils.S_IRWXG); + 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() + "/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); + mode = JnaUtils.getFilemode(folder.getAbsolutePath() + "/config"); + assertEquals(JnaUtils.S_IRGRP | JnaUtils.S_IWGRP, mode & JnaUtils.S_IRWXG); + } repository.close(); RepositoryCache.close(repository); diff --git a/src/test/java/com/gitblit/tests/JnaUtilsTest.java b/src/test/java/com/gitblit/tests/JnaUtilsTest.java index 574686ba..2430b6ea 100644 --- a/src/test/java/com/gitblit/tests/JnaUtilsTest.java +++ b/src/test/java/com/gitblit/tests/JnaUtilsTest.java @@ -37,64 +37,78 @@ 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()); + 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 + 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 + 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()); + 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()); + 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 + 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 + 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 + 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 + 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()); + repository.close(); + RepositoryCache.close(repository); + FileUtils.deleteDirectory(repository.getDirectory()); + } } } -- cgit v1.2.3 From 8b5730a0e32d5707b6ac6df5fb0906b7981853eb Mon Sep 17 00:00:00 2001 From: Florian Zschocke Date: Tue, 20 Aug 2013 21:20:17 +0200 Subject: Fix setting wrrong custom mode on file and in config. --- src/main/java/com/gitblit/utils/JGitUtils.java | 7 +++-- src/test/java/com/gitblit/tests/JGitUtilsTest.java | 36 ++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) (limited to 'src/test/java') diff --git a/src/main/java/com/gitblit/utils/JGitUtils.java b/src/main/java/com/gitblit/utils/JGitUtils.java index 57bb147f..66dbd60d 100644 --- a/src/main/java/com/gitblit/utils/JGitUtils.java +++ b/src/main/java/com/gitblit/utils/JGitUtils.java @@ -353,7 +353,10 @@ public class JGitUtils { } String getValue() { - if ( enumValue == GitConfigSharedRepositoryValue.Oxxx ) return Integer.toOctalString(intValue); + if ( enumValue == GitConfigSharedRepositoryValue.Oxxx ) { + if (intValue == 0) return "0"; + return String.format("0%o", intValue); + } return enumValue.getConfigValue(); } @@ -410,7 +413,7 @@ public class JGitUtils { if (configShared.isCustom()) { // Use the custom value for access permissions. - mode |= (mode & ~0777) | perm; + mode = (mode & ~0777) | perm; } else { // Just add necessary bits to existing permissions. diff --git a/src/test/java/com/gitblit/tests/JGitUtilsTest.java b/src/test/java/com/gitblit/tests/JGitUtilsTest.java index f18c05f8..cdf698d6 100644 --- a/src/test/java/com/gitblit/tests/JGitUtilsTest.java +++ b/src/test/java/com/gitblit/tests/JGitUtilsTest.java @@ -182,6 +182,42 @@ public class JGitUtilsTest { } } + @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 testRefs() throws Exception { Repository repository = GitBlitSuite.getJGitRepository(); -- cgit v1.2.3 From b724448b589d60a9a7dda60cf30741048c98e199 Mon Sep 17 00:00:00 2001 From: Florian Zschocke Date: Wed, 21 Aug 2013 10:39:43 +0200 Subject: Fix set-gid bit clearing under Linux when effective gid is different from file gid. --- src/main/java/com/gitblit/utils/JGitUtils.java | 16 +++- src/main/java/com/gitblit/utils/JnaUtils.java | 90 ++++++++++++++++++++-- src/test/java/com/gitblit/tests/JGitUtilsTest.java | 64 +++++++++++++++ src/test/java/com/gitblit/tests/JnaUtilsTest.java | 38 +++++++++ 4 files changed, 201 insertions(+), 7 deletions(-) (limited to 'src/test/java') diff --git a/src/main/java/com/gitblit/utils/JGitUtils.java b/src/main/java/com/gitblit/utils/JGitUtils.java index 66dbd60d..2e448c36 100644 --- a/src/main/java/com/gitblit/utils/JGitUtils.java +++ b/src/main/java/com/gitblit/utils/JGitUtils.java @@ -403,9 +403,23 @@ public class JGitUtils { if (! path.exists()) return -1; int perm = configShared.getPerm(); - int mode = JnaUtils.getFilemode(path); + 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. diff --git a/src/main/java/com/gitblit/utils/JnaUtils.java b/src/main/java/com/gitblit/utils/JnaUtils.java index 3bf1f73a..4009342a 100644 --- a/src/main/java/com/gitblit/utils/JnaUtils.java +++ b/src/main/java/com/gitblit/utils/JnaUtils.java @@ -79,6 +79,28 @@ public class JnaUtils { 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(); } @@ -157,21 +179,77 @@ public class JnaUtils { 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 @@ -227,12 +305,12 @@ public class JnaUtils { } } - 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. @@ -240,7 +318,7 @@ public class JnaUtils { */ 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; diff --git a/src/test/java/com/gitblit/tests/JGitUtilsTest.java b/src/test/java/com/gitblit/tests/JGitUtilsTest.java index cdf698d6..463c0a84 100644 --- a/src/test/java/com/gitblit/tests/JGitUtilsTest.java +++ b/src/test/java/com/gitblit/tests/JGitUtilsTest.java @@ -218,6 +218,70 @@ public class JGitUtilsTest { } } + @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(); diff --git a/src/test/java/com/gitblit/tests/JnaUtilsTest.java b/src/test/java/com/gitblit/tests/JnaUtilsTest.java index 2430b6ea..25d1ccf5 100644 --- a/src/test/java/com/gitblit/tests/JnaUtilsTest.java +++ b/src/test/java/com/gitblit/tests/JnaUtilsTest.java @@ -20,6 +20,7 @@ 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; @@ -35,6 +36,24 @@ import org.junit.Test; */ 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()) { @@ -111,4 +130,23 @@ public class JnaUtilsTest { 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); + } + } + + } -- cgit v1.2.3