Skip to content

Commit

Permalink
Library code for user-relative paths, take three.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Andreas Ericsson authored and Junio C Hamano committed Nov 20, 2005
1 parent 942c1f5 commit 54f4b87
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 0 deletions.
1 change: 1 addition & 0 deletions cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
72 changes: 72 additions & 0 deletions path.c
Original file line number Diff line number Diff line change
Expand Up @@ -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/";
Expand Down Expand Up @@ -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;
}

0 comments on commit 54f4b87

Please sign in to comment.