summaryrefslogtreecommitdiff
path: root/path.c
diff options
context:
space:
mode:
authorAndreas Ericsson <exon@op5.se>2005-11-17 20:37:14 +0100
committerJunio C Hamano <junkio@cox.net>2005-11-19 20:50:37 -0800
commit54f4b87454824fedc629219620ce9b7cdcab3d27 (patch)
tree8b9b1ec83ab540627076b2fd36da56055be75d14 /path.c
parent942c1f53aef03cb3d8b5c39b38997a379c3fad20 (diff)
downloadgit-54f4b87454824fedc629219620ce9b7cdcab3d27.tar.gz
Library code for user-relative paths, take three.
This patch provides the work-horse of the user-relative paths feature, using Linus' idea of a blind chdir() and getcwd() which makes it remarkably simple. Signed-off-by: Andreas Ericsson <ae@op5.se> Signed-off-by: Junio C Hamano <junkio@cox.net>
Diffstat (limited to 'path.c')
-rw-r--r--path.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/path.c b/path.c
index 495d17ca4c..5b617092ad 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 char *src, size_t n)
return dest;
}
+
+static 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(char *path, int strict)
+{
+ char *dir = path;
+
+ if(strict && *dir != '/')
+ return NULL;
+
+ if(*dir == '~') { /* user-relative path */
+ struct passwd *pw;
+ char *slash = strchr(dir, '/');
+
+ dir++;
+ /* '~/' and '~' (no slash) means users own home-dir */
+ if(!*dir || *dir == '/')
+ pw = getpwuid(getuid());
+ else {
+ if (slash) {
+ *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]) /* no path following username */
+ return current_dir();
+
+ dir = slash + 1;
+ }
+
+ /* ~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();
+}
+
+char *enter_repo(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;
+}