diff options
author | Andreas Ericsson <exon@op5.se> | 2005-11-17 20:37:14 +0100 |
---|---|---|
committer | Junio C Hamano <junkio@cox.net> | 2005-11-19 20:50:37 -0800 |
commit | 54f4b87454824fedc629219620ce9b7cdcab3d27 (patch) | |
tree | 8b9b1ec83ab540627076b2fd36da56055be75d14 /path.c | |
parent | 942c1f53aef03cb3d8b5c39b38997a379c3fad20 (diff) | |
download | git-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.c | 72 |
1 files changed, 72 insertions, 0 deletions
@@ -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; +} |