From 54f4b87454824fedc629219620ce9b7cdcab3d27 Mon Sep 17 00:00:00 2001 From: Andreas Ericsson Date: Thu, 17 Nov 2005 20:37:14 +0100 Subject: 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 Signed-off-by: Junio C Hamano --- cache.h | 1 + path.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/cache.h b/cache.h index f93f516815..e2be3e7b0e 100644 --- a/cache.h +++ b/cache.h @@ -192,6 +192,7 @@ extern int diff_rename_limit_default; /* Return a statically allocated filename matching the sha1 signature */ extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); +extern char *enter_repo(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 495d17ca4c..5b617092ad 100644 --- a/path.c +++ b/path.c @@ -11,6 +11,7 @@ * which is what it's designed for. */ #include "cache.h" +#include 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; +} -- cgit v1.2.1