Verify the case of the project name before opening git repository

When a project is not in the project cache, Gerrit checks for the
corresponding git repository in the file system and adds the project
to the cache if the git repository is found. On Windows the paths are
case-insensitive, which means that the lookup for the git repository
in the file system is even successfull if the name of the project was
given in an incorrect case.

E.g. lets assume the project 'test/myProject' exists, then asking the
project cache for 'test/myProject', 'TEST/myProject', 'test/MyProject'
would all succeed. Even worse for each variant of the case a new
instance of the project would be added to the cache. These instances
of the same project in the project cache might even become
inconsistent with each other.

This problem is relevant for all SSH commands where the user can
specify a project name, e.g. for 'set-project-parent'. If for the
'--parent' parameter the project is specified in an incorrect case,
this incorrect case is then even persisted in the 'project.config'
file of the child projects.

To avoid these problems, with this change the case of the project name
is now verified and the project is only added to the cache if the
project name was specified in the correct case. If the project name
was specified in an incorrect case the lookup would fail with an
RepositoryNotFoundException.

Change-Id: Icf826d16e05a8c19537e86fe302b158bcb407bba
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
Edwin Kempin
2011-09-06 16:43:30 +02:00
parent 813123b520
commit a7e928daaf
3 changed files with 128 additions and 43 deletions

View File

@@ -29,6 +29,7 @@ import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.git.ReplicationQueue;
import com.google.gerrit.server.git.RepositoryCaseMismatchException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.sshd.BaseCommand;
@@ -178,18 +179,9 @@ final class CreateProject extends BaseCommand {
repo.close();
}
} catch (IllegalStateException err) {
try {
Repository repo = repoManager.openRepository(nameKey);
try {
if (repo.getObjectDatabase().exists()) {
throw new UnloggedFailure(1, "fatal: project \"" + projectName + "\" exists");
}
} finally {
repo.close();
}
} catch (RepositoryNotFoundException doesNotExist) {
throw new Failure(1, "fatal: Cannot create " + projectName, err);
}
handleRepositoryExistsException(nameKey);
} catch (RepositoryCaseMismatchException err) {
handleRepositoryExistsException(err.getNameOfExistingProject());
} catch (RepositoryNotFoundException badName) {
throw new UnloggedFailure(1, "fatal: " + badName.getMessage());
} catch (Exception err) {
@@ -297,4 +289,21 @@ final class CreateProject extends BaseCommand {
throw new Failure(1, "--branch \"" + branch + "\" is not a valid name");
}
}
private void handleRepositoryExistsException(final Project.NameKey projectName)
throws Failure {
try {
Repository repo = repoManager.openRepository(projectName);
try {
if (repo.getObjectDatabase().exists()) {
throw new UnloggedFailure(1, "fatal: project \"" + projectName
+ "\" exists");
}
} finally {
repo.close();
}
} catch (RepositoryNotFoundException err) {
throw new Failure(1, "fatal: Cannot create " + projectName, err);
}
}
}