# [PATCH 2/4] Library code for user-relative paths.

3 messages from 2005-11-01 to 2005-11-02. Participants: Andreas Ericsson, Junio C Hamano.
Thread: https://gitlist.dev/t/2301

## Andreas Ericsson, 2005-11-01 22:59

Subject: [PATCH 2/4] Library code for user-relative paths.
Message-ID: <20051101225921.2C6035BA82@nox.op5.se>
URL: https://gitlist.dev/e/20051101225921.2C6035BA82%40nox.op5.se

```
See this discussion, "[RFC] GIT paths", on the git-list:
http://www.gelato.unsw.edu.au/archives/git/0510/10924.html

This patch provides the work-horse of the user-relative paths, using Linus'
idea of a blind chdir() and getcwd(), which makes it remarkably simple.

Signed-off-by: Andreas Ericsson <ae@op5.se>

---

 cache.h |    1 +
 path.c  |   72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+), 0 deletions(-)

applies-to: bf640ae3d5bb5f5f283c62d4f5198a3c5e5086f0
1c4e7bb2383e2b67f0e877a46ea1eba4ec7e45e7
diff --git a/cache.h b/cache.h
index 677c6ac..aea2097 100644
--- a/cache.h
+++ b/cache.h
@@ -190,6 +190,7 @@ extern int trust_executable_bit;
 
 /* Return a statically allocated filename matching the sha1 signature */
 extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
+extern const char *is_git_repo(const char *path, int strict);
 extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 extern char *sha1_file_name(const unsigned char *sha1);
 extern char *sha1_pack_name(const unsigned char *sha1);
diff --git a/path.c b/path.c
index 495d17c..4f4018d 100644
--- a/path.c
+++ b/path.c
@@ -11,6 +11,7 @@
  * which is what it's designed for.
  */
 #include "cache.h"
+#include <pwd.h>
 
 static char pathname[PATH_MAX];
 static char bad_path[] = "/bad-path/";
@@ -89,3 +90,74 @@ char *safe_strncpy(char *dest, const cha
 
 	return dest;
 }
+
+static const char *current_dir()
+{
+	return getcwd(pathname, sizeof(pathname));
+}
+
+/* Take a raw path from is_git_repo() and canonicalize it using Linus'
+ * idea of a blind chdir() and getcwd(). */
+static const char *canonical_path(const char *path, int strict)
+{
+	const char *dir = path;
+
+	if(strict && *dir != '/')
+		return NULL;
+
+	if(*dir == '~') {		/* user-relative path */
+		struct passwd *pw;
+		char *slash = NULL;
+
+		dir++;
+		/* '~/' and '~' (no slash) means users own home-dir */
+		if(!*dir || *dir == '/')
+			pw = getpwuid(getuid());
+		else {
+			if((slash = strchr(dir, '/'))) {
+				*slash = '\0';
+				pw = getpwnam(dir);
+				*slash = '/';
+			}
+			else
+				pw = getpwnam(dir);
+		}
+
+		/* make sure we got something back that we can chdir() to */
+		if(!pw || chdir(pw->pw_dir) < 0)
+			return NULL;
+
+		if(slash && *slash + 1)
+			dir = slash + 1;
+		else
+			dir = current_dir();
+	}
+
+	/* ~foo/path/to/repo is now path/to/repo and we're in foo's homedir */
+	if(chdir(dir) < 0)
+		return NULL;
+
+	return current_dir();
+}
+
+const char *is_git_repo(const char *path, int strict)
+{
+	if(!path)
+		return NULL;
+
+	if(!canonical_path(path, strict)) {
+		if(strict || !canonical_path(mkpath("%s.git", path), strict))
+			return NULL;
+	}
+
+	/* This is perfectly safe, and people tend to think of the directory
+	 * where they ran git-init-db as their repository, so humour them. */
+	(void)chdir(".git");
+
+	if(access("objects", X_OK) == 0 && access("refs", X_OK) == 0) {
+		putenv("GIT_DIR=.");
+		return current_dir();
+	}
+
+	return NULL;
+}
---
0.99.9.GIT

```

## Junio C Hamano, 2005-11-02 00:14

Subject: Re: [PATCH 2/4] Library code for user-relative paths.
Message-ID: <7vk6fr6h3j.fsf@assigned-by-dhcp.cox.net>
URL: https://gitlist.dev/e/7vk6fr6h3j.fsf%40assigned-by-dhcp.cox.net
In-Reply-To: <20051101225921.2C6035BA82@nox.op5.se>

```
Andreas Ericsson <ae@op5.se> writes:

> +			if((slash = strchr(dir, '/'))) {
> +				*slash = '\0';
> +				pw = getpwnam(dir);
> +				*slash = '/';

Should you be writing into *slash when dir and path are const
char *?  I know strchr returns "char *" and the compiler would
not complain but this sounds somewhat yucky.

> +		if(slash && *slash + 1)

I think you mean "if (slash && slash[1])" here.  While we are at
it, please have a SP betweeen if and open parenthesis.

> +			dir = slash + 1;
> +		else
> +			dir = current_dir();
> +	}
> +
> +	/* ~foo/path/to/repo is now path/to/repo and we're in foo's homedir */
> +	if(chdir(dir) < 0)
> +		return NULL;

Hmm.  It's not wrong, but "dir = current_dir()" immediately
followed by "chdir(dir)" does not feel right.

```

## Andreas Ericsson, 2005-11-02 08:40

Subject: Re: [PATCH 2/4] Library code for user-relative paths.
Message-ID: <43687B80.1020600@op5.se>
URL: https://gitlist.dev/e/43687B80.1020600%40op5.se
In-Reply-To: <7vk6fr6h3j.fsf@assigned-by-dhcp.cox.net>

```
Junio C Hamano wrote:
> Andreas Ericsson <ae@op5.se> writes:
> 
> 
>>+			if((slash = strchr(dir, '/'))) {
>>+				*slash = '\0';
>>+				pw = getpwnam(dir);
>>+				*slash = '/';
> 
> 
> Should you be writing into *slash when dir and path are const
> char *?  I know strchr returns "char *" and the compiler would
> not complain but this sounds somewhat yucky.
> 

True. Although path isn't, strictly speaking, const char *, so perhaps 
that's what needs fixing. It's only ever called with path coming from 
argv, which isn't const. I can't really imagine anywhere where the 
repo-path might be const char * now that I think of it.

> 
>>+		if(slash && *slash + 1)
> 
> 
> I think you mean "if (slash && slash[1])" here.  While we are at
> it, please have a SP betweeen if and open parenthesis.
> 

Actually *(slash + 1), but it amounts to the same thing I suppose. ;)

I looked around for indentation guide-lines but didn't found any, and 
the current code isn't exactly consistent about it. Perhaps it needs adding?

> 
>>+			dir = slash + 1;
>>+		else
>>+			dir = current_dir();
>>+	}
>>+
>>+	/* ~foo/path/to/repo is now path/to/repo and we're in foo's homedir */
>>+	if(chdir(dir) < 0)
>>+		return NULL;
> 
> 
> Hmm.  It's not wrong, but "dir = current_dir()" immediately
> followed by "chdir(dir)" does not feel right.
> 

It could be "return current_dir();" immediately, I suppose. Would that 
be satisfactory?

-- 
Andreas Ericsson                   andreas.ericsson@op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

```
