threads / patch / 22651

v3, 5 partsmake_absolute_path(): Do not append redundant slash

Subject: [PATCH v3 1/5] make_absolute_path(): Do not append redundant slash

## tl;dr

8 messages between Feb 14, 2010 and Feb 16, 2010. Diffs are folded; open one to read it.

replies: 7people: 2as markdown or json

Nguyễn Thái Ngọc Duy· Feb 14, 2010, 15:44 UTC · lore

When concatenating two paths, if the first one already have '/', do not put another '/' in between the two paths.

Usually this is not the case as getcwd() won't return '/foo/bar/', except when you are standing at root, then it will return '/'.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 abspath.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)
Show changes to abspath.c +3 −2
diff --git a/abspath.c b/abspath.c
index b88122c..c91a29c 100644
--- a/abspath.c
+++ b/abspath.c
@@ -54,8 +54,9 @@ const char *make_absolute_path(const char *path)
 			if (len + strlen(last_elem) + 2 > PATH_MAX)
 				die ("Too long path name: '%s/%s'",
 						buf, last_elem);
-			buf[len] = '/';
-			strcpy(buf + len + 1, last_elem);
+			if (len && buf[len-1] != '/')
+				buf[len++] = '/';
+			strcpy(buf + len, last_elem);
 			free(last_elem);
 			last_elem = NULL;
 		}
-- 
1.7.0.195.g637a2
Nguyễn Thái Ngọc Duy· Feb 14, 2010, 15:44 UTC · re: Nguyễn Thái Ngọc Duy · lore

[PATCH v3 2/5] init-db, rev-parse --git-dir: do not append redundant slash

If git_dir already has the trailing slash, don't put another one before .git. This only happens when git_dir is '/' or 'C:/'

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin-init-db.c   |    9 ++++++---
 builtin-rev-parse.c |    4 +++-
 2 files changed, 9 insertions(+), 4 deletions(-)
Show changes to 2 files +9 −4

builtin-init-db.c, builtin-rev-parse.c

diff --git a/builtin-init-db.c b/builtin-init-db.c
index dd84cae..aae7a4d 100644
--- a/builtin-init-db.c
+++ b/builtin-init-db.c
@@ -331,11 +331,14 @@ int init_db(const char *template_dir, unsigned int flags)
 		git_config_set("receive.denyNonFastforwards", "true");
 	}
 
-	if (!(flags & INIT_DB_QUIET))
-		printf("%s%s Git repository in %s/\n",
+	if (!(flags & INIT_DB_QUIET)) {
+		const char *git_dir = get_git_dir();
+		int len = strlen(git_dir);
+		printf("%s%s Git repository in %s%s\n",
 		       reinit ? "Reinitialized existing" : "Initialized empty",
 		       shared_repository ? " shared" : "",
-		       get_git_dir());
+		       git_dir, len && git_dir[len-1] != '/' ? "/" : "");
+	}
 
 	return 0;
 }
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index a8c5043..88bad9a 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -637,6 +637,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 			if (!strcmp(arg, "--git-dir")) {
 				const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
 				static char cwd[PATH_MAX];
+				int len;
 				if (gitdir) {
 					puts(gitdir);
 					continue;
@@ -647,7 +648,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 				}
 				if (!getcwd(cwd, PATH_MAX))
 					die_errno("unable to get current working directory");
-				printf("%s/.git\n", cwd);
+				len = strlen(cwd);
+				printf("%s%s.git\n", cwd, len && cwd[len-1] != '/' ? "/" : "");
 				continue;
 			}
 			if (!strcmp(arg, "--is-inside-git-dir")) {
-- 
1.7.0.195.g637a2
Nguyễn Thái Ngọc Duy· Feb 14, 2010, 15:44 UTC · re: Nguyễn Thái Ngọc Duy · lore

[PATCH v3 3/5] Move offset_1st_component() to path.c

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 cache.h     |    1 +
 path.c      |    7 +++++++
 sha1_file.c |    7 -------
 3 files changed, 8 insertions(+), 7 deletions(-)
Show changes to 3 files +8 −7

cache.h, path.c, sha1_file.c

diff --git a/cache.h b/cache.h
index d478eff..ff23cd1 100644
--- a/cache.h
+++ b/cache.h
@@ -675,6 +675,7 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
+int offset_1st_component(const char *path);
 
 /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
 extern int sha1_object_info(const unsigned char *, unsigned long *);
diff --git a/path.c b/path.c
index 0005df3..fd70e88 100644
--- a/path.c
+++ b/path.c
@@ -649,3 +649,10 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
+
+int offset_1st_component(const char *path)
+{
+	if (has_dos_drive_prefix(path))
+		return 2 + (path[2] == '/');
+	return *path == '/';
+}
diff --git a/sha1_file.c b/sha1_file.c
index 657825e..52052b9 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -35,13 +35,6 @@ static size_t sz_fmt(size_t s) { return s; }
 
 const unsigned char null_sha1[20];
 
-static inline int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + (path[2] == '/');
-	return *path == '/';
-}
-
 int safe_create_leading_directories(char *path)
 {
 	char *pos = path + offset_1st_component(path);
-- 
1.7.0.195.g637a2
Johannes Sixt· Feb 15, 2010, 19:43 UTC · re: Nguyễn Thái Ngọc Duy · lore

Re: [PATCH v3 3/5] Move offset_1st_component() to path.c

Nguyễn Thái Ngọc Duy schrieb:
Show 6 quoted lines
> +int offset_1st_component(const char *path)
> +{
> +	if (has_dos_drive_prefix(path))
> +		return 2 + (path[2] == '/');
> +	return *path == '/';
> +}

I'd have expected that you future-proofed this function by using is_dir_sep() or even use your previous implementation of is_root_path (because this implementation is a bit cryptic).

But if the new callers of this function will only pass the results of normalize_path_copy() and getcwd() (both return only forward-slashes on Windows), then I'm fine with this version. Do they?

-- Hannes
=?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?=· Feb 16, 2010, 05:22 UTC · re: Johannes Sixt · lore

[PATCH v3 3/5] Move offset_1st_component() to path.c

The implementation is also lightly modified to use is_dir_sep() instead of hardcoding '/'.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
  On Mon, Feb 15, 2010 at 08:43:41PM +0100, Johannes Sixt wrote:
  > Nguyễn Thái Ngọc Duy schrieb:
  >> +int offset_1st_component(const char *path)
  >> +{
  >> +	if (has_dos_drive_prefix(path))
  >> +		return 2 + (path[2] == '/');
  >> +	return *path == '/';
  >> +}
  >
  > I'd have expected that you future-proofed this function by using 
  > is_dir_sep() or even use your previous implementation of is_root_path 
  > (because this implementation is a bit cryptic).
  >
  > But if the new callers of this function will only pass the results of 
  > normalize_path_copy() and getcwd() (both return only forward-slashes on 
  > Windows), then I'm fine with this version. Do they?
  They do. But future-proofing can never be a bad thing.
 cache.h     |    1 +
 path.c      |   10 ++++++++++
 sha1_file.c |    7 -------
 3 files changed, 11 insertions(+), 7 deletions(-)
Show changes to 3 files +11 −7

cache.h, path.c, sha1_file.c

diff --git a/cache.h b/cache.h
index d478eff..ff23cd1 100644
--- a/cache.h
+++ b/cache.h
@@ -675,6 +675,7 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
+int offset_1st_component(const char *path);
 
 /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
 extern int sha1_object_info(const unsigned char *, unsigned long *);
diff --git a/path.c b/path.c
index 0005df3..6304805 100644
--- a/path.c
+++ b/path.c
@@ -649,3 +649,13 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
+
+int offset_1st_component(const char *path)
+{
+	int len = 0;
+	if (has_dos_drive_prefix(path))
+		len += 2;
+	if (is_dir_sep(path[len]))
+		return len++;
+	return len;
+}
diff --git a/sha1_file.c b/sha1_file.c
index 657825e..52052b9 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -35,13 +35,6 @@ static size_t sz_fmt(size_t s) { return s; }
 
 const unsigned char null_sha1[20];
 
-static inline int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + (path[2] == '/');
-	return *path == '/';
-}
-
 int safe_create_leading_directories(char *path)
 {
 	char *pos = path + offset_1st_component(path);
-- 
1.7.0.195.g637a2
Johannes Sixt· Feb 16, 2010, 19:47 UTC · re: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= · lore

Re: [PATCH v3 3/5] Move offset_1st_component() to path.c

Nguyễn Thái Ngọc Duy schrieb:
Show 8 quoted lines
>   > is_dir_sep() or even use your previous implementation of is_root_path 
>   > (because this implementation is a bit cryptic).
>   >
>   > But if the new callers of this function will only pass the results of 
>   > normalize_path_copy() and getcwd() (both return only forward-slashes on 
>   > Windows), then I'm fine with this version. Do they?
> 
>   They do. But future-proofing can never be a bad thing.
Thanks, but...
Show 7 quoted lines
> +int offset_1st_component(const char *path)
> +{
> +	int len = 0;
> +	if (has_dos_drive_prefix(path))
> +		len += 2;
> +	if (is_dir_sep(path[len]))
> +		return len++;
oops, does this work at all for you? You must not have 'return' here.
> +	return len;
> +}
-- Hannes
Nguyễn Thái Ngọc Duy· Feb 14, 2010, 15:44 UTC · re: Nguyễn Thái Ngọc Duy · lore

[PATCH v3 4/5] Support working directory located at root

Git should work regardless where the working directory is located, even at root. This patch fixes two places where it assumes working directory always have parent directory.

In setup_git_directory_gently(), when Git goes up to root and finds .git there, it happily sets worktree to "" instead of "/".

In prefix_path(), loosen the outside repo check a little bit. Usually when a path XXX is inside worktree /foo, it must be either "/foo", or "/foo/...". When worktree is simply "/", we can safely ignore the check: we have a slash at the beginning already.

Not related to worktree, but also set gitdir correctly if a bare repo is placed (insanely?) at root.

Thanks João Carlos Mendes Luís for pointing out this problem.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 setup.c |   13 ++++++++-----
 1 files changed, 8 insertions(+), 5 deletions(-)
Show changes to setup.c +8 −5
diff --git a/setup.c b/setup.c
index b38cbee..08df00e 100644
--- a/setup.c
+++ b/setup.c
@@ -18,14 +18,15 @@ const char *prefix_path(const char *prefix, int len, const char *path)
 	if (normalize_path_copy(sanitized, sanitized))
 		goto error_out;
 	if (is_absolute_path(orig)) {
-		size_t len, total;
+		size_t root_len, len, total;
 		const char *work_tree = get_git_work_tree();
 		if (!work_tree)
 			goto error_out;
 		len = strlen(work_tree);
+		root_len = offset_1st_component(work_tree);
 		total = strlen(sanitized) + 1;
 		if (strncmp(sanitized, work_tree, len) ||
-		    (sanitized[len] != '\0' && sanitized[len] != '/')) {
+		    (len > root_len && sanitized[len] != '\0' && sanitized[len] != '/')) {
 		error_out:
 			die("'%s' is outside repository", orig);
 		}
@@ -321,7 +322,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
 	static char cwd[PATH_MAX+1];
 	const char *gitdirenv;
 	const char *gitfile_dir;
-	int len, offset, ceil_offset;
+	int len, offset, ceil_offset, root_len;
 
 	/*
 	 * Let's assume that we are in a git repository.
@@ -403,7 +404,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
 			if (!work_tree_env)
 				inside_work_tree = 0;
 			if (offset != len) {
-				cwd[offset] = '\0';
+				root_len = offset_1st_component(cwd);
+				cwd[offset > root_len ? offset : root_len] = '\0';
 				set_git_dir(cwd);
 			} else
 				set_git_dir(".");
@@ -427,7 +429,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
 	inside_git_dir = 0;
 	if (!work_tree_env)
 		inside_work_tree = 1;
-	git_work_tree_cfg = xstrndup(cwd, offset);
+	root_len = offset_1st_component(cwd);
+	git_work_tree_cfg = xstrndup(cwd, offset > root_len ? offset : root_len);
 	if (check_repository_format_gently(nongit_ok))
 		return NULL;
 	if (offset == len)
-- 
1.7.0.195.g637a2
Nguyễn Thái Ngọc Duy· Feb 14, 2010, 15:44 UTC · re: Nguyễn Thái Ngọc Duy · lore

[PATCH v3 5/5] Add test for using Git at root of file system

This kind of test requires a throw-away root filesystem so that it can play on. If you have such a system, go ahead, "chmod 777 /" and run this test manually. Because this is a dangerous test, you are required to set an env variable, and not to use root to run it.

Script prepare-root.sh may help you set up a chroot environment with Git test suite inside. You will need Linux, static linked busybox, rsync and root permission to use it.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 t/t1509-root-worktree.sh  |  249 +++++++++++++++++++++++++++++++++++++++++++++
 t/t1509/excludes          |   14 +++
 t/t1509/prepare-chroot.sh |   38 +++++++
 3 files changed, 301 insertions(+), 0 deletions(-)
 create mode 100755 t/t1509-root-worktree.sh
 create mode 100644 t/t1509/excludes
 create mode 100755 t/t1509/prepare-chroot.sh
Show changes to 3 files +301 −0

t/t1509-root-worktree.sh, t/t1509/excludes, t/t1509/prepare-chroot.sh

diff --git a/t/t1509-root-worktree.sh b/t/t1509-root-worktree.sh
new file mode 100755
index 0000000..5322a3b
--- /dev/null
+++ b/t/t1509-root-worktree.sh
@@ -0,0 +1,249 @@
+#!/bin/sh
+
+test_description='Test Git when git repository is located at root
+
+This test requires write access in root. Do not bother if you do not
+have a throwaway chroot or VM.
+
+Script t1509/prepare-chroot.sh may help you setup chroot, then you
+can chroot in and execute this test from there.
+'
+
+. ./test-lib.sh
+
+test_cmp_val() {
+	echo "$1" > expected
+	echo "$2" > result
+	test_cmp expected result
+}
+
+test_vars() {
+	test_expect_success "$1: gitdir" '
+		test_cmp_val "'"$2"'" "$(git rev-parse --git-dir)"
+	'
+
+	test_expect_success "$1: worktree" '
+		test_cmp_val "'"$3"'" "$(git rev-parse --show-toplevel)"
+	'
+
+	test_expect_success "$1: prefix" '
+		test_cmp_val "'"$4"'" "$(git rev-parse --show-prefix)"
+	'
+}
+
+test_foobar_root() {
+	test_expect_success 'add relative' '
+		test -z "$(cd / && git ls-files)" &&
+		git add foo/foome &&
+		git add foo/bar/barme &&
+		git add me &&
+		( cd / && git ls-files --stage ) > result &&
+		test_cmp /ls.expected result &&
+		rm "$(git rev-parse --git-dir)/index"
+	'
+
+	test_expect_success 'add absolute' '
+		test -z "$(cd / && git ls-files)" &&
+		git add /foo/foome &&
+		git add /foo/bar/barme &&
+		git add /me &&
+		( cd / && git ls-files --stage ) > result &&
+		test_cmp /ls.expected result &&
+		rm "$(git rev-parse --git-dir)/index"
+	'
+
+}
+
+test_foobar_foo() {
+	test_expect_success 'add relative' '
+		test -z "$(cd / && git ls-files)" &&
+		git add foome &&
+		git add bar/barme &&
+		git add ../me &&
+		( cd / && git ls-files --stage ) > result &&
+		test_cmp /ls.expected result &&
+		rm "$(git rev-parse --git-dir)/index"
+	'
+
+	test_expect_success 'add absolute' '
+		test -z "$(cd / && git ls-files)" &&
+		git add /foo/foome &&
+		git add /foo/bar/barme &&
+		git add /me &&
+		( cd / && git ls-files --stage ) > result &&
+		test_cmp /ls.expected result &&
+		rm "$(git rev-parse --git-dir)/index"
+	'
+}
+
+test_foobar_foobar() {
+	test_expect_success 'add relative' '
+		test -z "$(cd / && git ls-files)" &&
+		git add ../foome &&
+		git add barme &&
+		git add ../../me &&
+		( cd / && git ls-files --stage ) > result &&
+		test_cmp /ls.expected result &&
+		rm "$(git rev-parse --git-dir)/index"
+	'
+
+	test_expect_success 'add absolute' '
+		test -z "$(cd / && git ls-files)" &&
+		git add /foo/foome &&
+		git add /foo/bar/barme &&
+		git add /me &&
+		( cd / && git ls-files --stage ) > result &&
+		test_cmp /ls.expected result &&
+		rm "$(git rev-parse --git-dir)/index"
+	'
+}
+
+if ! test_have_prereq POSIXPERM || ! [ -w / ]; then
+	say "Dangerous test skipped. Read this test if you want to execute it"
+	test_done
+fi
+
+if [ "$IKNOWWHATIAMDOING" != "YES" ]; then
+	say "You must set env var IKNOWWHATIAMDOING=YES in order to run this test"
+	test_done
+fi
+
+if [ "$UID" = 0 ]; then
+	say "No you can't run this with root"
+	test_done
+fi
+
+ONE_SHA1=d00491fd7e5bb6fa28c517a0bb32b8b506539d4d
+
+test_expect_success 'setup' '
+	rm -rf /foo
+	mkdir /foo &&
+	mkdir /foo/bar &&
+	echo 1 > /foo/foome &&
+	echo 1 > /foo/bar/barme &&
+	echo 1 > /me
+'
+
+say "GIT_DIR absolute, GIT_WORK_TREE set"
+
+test_expect_success 'go to /' 'cd /'
+
+cat >ls.expected <<EOF
+100644 $ONE_SHA1 0	foo/bar/barme
+100644 $ONE_SHA1 0	foo/foome
+100644 $ONE_SHA1 0	me
+EOF
+
+export GIT_DIR="$TRASH_DIRECTORY/.git"
+export GIT_WORK_TREE=/
+
+test_vars 'abs gitdir, root' "$GIT_DIR" "/" ""
+test_foobar_root
+
+test_expect_success 'go to /foo' 'cd /foo'
+
+test_vars 'abs gitdir, foo' "$GIT_DIR" "/" "foo/"
+test_foobar_foo
+
+test_expect_success 'go to /foo/bar' 'cd /foo/bar'
+
+test_vars 'abs gitdir, foo/bar' "$GIT_DIR" "/" "foo/bar/"
+test_foobar_foobar
+
+say "GIT_DIR relative, GIT_WORK_TREE set"
+
+test_expect_success 'go to /' 'cd /'
+
+export GIT_DIR="$(echo $TRASH_DIRECTORY|sed 's,^/,,')/.git"
+export GIT_WORK_TREE=/
+
+test_vars 'rel gitdir, root' "$GIT_DIR" "/" ""
+test_foobar_root
+
+test_expect_success 'go to /foo' 'cd /foo'
+
+export GIT_DIR="../$TRASH_DIRECTORY/.git"
+export GIT_WORK_TREE=/
+
+test_vars 'rel gitdir, foo' "$TRASH_DIRECTORY/.git" "/" "foo/"
+test_foobar_foo
+
+test_expect_success 'go to /foo/bar' 'cd /foo/bar'
+
+export GIT_DIR="../../$TRASH_DIRECTORY/.git"
+export GIT_WORK_TREE=/
+
+test_vars 'rel gitdir, foo/bar' "$TRASH_DIRECTORY/.git" "/" "foo/bar/"
+test_foobar_foobar
+
+say "GIT_DIR relative, GIT_WORK_TREE relative"
+
+test_expect_success 'go to /' 'cd /'
+
+export GIT_DIR="$(echo $TRASH_DIRECTORY|sed 's,^/,,')/.git"
+export GIT_WORK_TREE=.
+
+test_vars 'rel gitdir, root' "$GIT_DIR" "/" ""
+test_foobar_root
+
+test_expect_success 'go to /' 'cd /foo'
+
+export GIT_DIR="../$TRASH_DIRECTORY/.git"
+export GIT_WORK_TREE=..
+
+test_vars 'rel gitdir, foo' "$TRASH_DIRECTORY/.git" "/" "foo/"
+test_foobar_foo
+
+test_expect_success 'go to /foo/bar' 'cd /foo/bar'
+
+export GIT_DIR="../../$TRASH_DIRECTORY/.git"
+export GIT_WORK_TREE=../..
+
+test_vars 'rel gitdir, foo/bar' "$TRASH_DIRECTORY/.git" "/" "foo/bar/"
+test_foobar_foobar
+
+say ".git at root"
+
+unset GIT_DIR
+unset GIT_WORK_TREE
+
+test_expect_success 'go to /' 'cd /'
+test_expect_success 'setup' '
+	rm -rf /.git
+	echo "Initialized empty Git repository in /.git/" > expected &&
+	git init > result &&
+	test_cmp expected result
+'
+
+test_vars 'auto gitdir, root' ".git" "/" ""
+test_foobar_root
+
+test_expect_success 'go to /foo' 'cd /foo'
+test_vars 'auto gitdir, foo' "/.git" "/" "foo/"
+test_foobar_foo
+
+test_expect_success 'go to /foo/bar' 'cd /foo/bar'
+test_vars 'auto gitdir, foo/bar' "/.git" "/" "foo/bar/"
+test_foobar_foobar
+
+test_expect_success 'cleanup' 'rm -rf /.git'
+
+say "auto bare gitdir"
+
+# DESTROYYYYY!!!!!
+test_expect_success 'setup' '
+	rm -rf /refs /objects /info /hooks
+	rm /*
+	cd / &&
+	echo "Initialized empty Git repository in /" > expected &&
+	git init --bare > result &&
+	test_cmp expected result
+'
+
+test_vars 'auto gitdir, root' "." "" ""
+
+test_expect_success 'go to /foo' 'cd /foo'
+
+test_vars 'auto gitdir, root' "/" "" ""
+
+test_done
diff --git a/t/t1509/excludes b/t/t1509/excludes
new file mode 100644
index 0000000..d4d21d3
--- /dev/null
+++ b/t/t1509/excludes
@@ -0,0 +1,14 @@
+*.o
+*~
+*.bak
+*.c
+*.h
+.git
+contrib
+Documentation
+git-gui
+gitk-git
+gitweb
+t/t4013
+t/t5100
+t/t5515
diff --git a/t/t1509/prepare-chroot.sh b/t/t1509/prepare-chroot.sh
new file mode 100755
index 0000000..c5334a8
--- /dev/null
+++ b/t/t1509/prepare-chroot.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+die() {
+	echo >&2 "$@"
+	exit 1
+}
+
+xmkdir() {
+	while [ -n "$1" ]; do
+		[ -d "$1" ] || mkdir "$1" || die "Unable to mkdir $1"
+		shift
+	done
+}
+
+R="$1"
+
+[ -n "$R" ] || die "Usage: prepare-chroot.sh <root>"
+[ -x git ] || die "This script needs to be executed at git source code's top directory"
+[ -x /bin/busybox ] || die "You need busybox"
+
+xmkdir "$R" "$R/bin" "$R/etc" "$R/lib" "$R/dev"
+[ -c "$R/dev/null" ] || die "/dev/null is missing. Do mknod $R/dev/null c 1 3 && chmod 666 $R/dev/null"
+echo "root:x:0:0:root:/:/bin/sh" > "$R/etc/passwd"
+echo "$(id -nu):x:$(id -u):$(id -g)::$(pwd)/t:/bin/sh" >> "$R/etc/passwd"
+echo "root::0:root" > "$R/etc/group"
+echo "$(id -ng)::$(id -g):$(id -nu)" >> "$R/etc/group"
+
+[ -x "$R/bin/busybox" ] || cp /bin/busybox "$R/bin/busybox"
+[ -x "$R/bin/sh" ] || ln -s /bin/busybox "$R/bin/sh"
+[ -x "$R/bin/su" ] || ln -s /bin/busybox "$R/bin/su"
+
+mkdir -p "$R$(pwd)"
+rsync --exclude-from t/t1509/excludes -Ha . "$R$(pwd)"
+ldd git | grep '/' | sed 's,.*\s\(/[^ ]*\).*,\1,' | while read i; do
+	mkdir -p "$R$(dirname $i)"
+	cp "$i" "$R/$i"
+done
+echo "Execute this in root: 'chroot $R /bin/su - $(id -nu)'"
-- 
1.7.0.195.g637a2

← back to recent threads